cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

sdl_check_compile.lua (11190B)


      1-- Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      2--
      3-- This software is provided 'as-is', without any express or implied
      4-- warranty.  In no event will the authors be held liable for any damages
      5-- arising from the use of this software.
      6--
      7-- Permission is granted to anyone to use this software for any purpose,
      8-- including commercial applications, and to alter it and redistribute it
      9-- freely.
     10--
     11-- Meta-build system using premake created and maintained by
     12-- Benjamin Henning <b.henning@digipen.edu>
     13
     14--[[
     15sdl_check_compile.lua
     16
     17	This file provides various utility functions which allow the meta-build
     18	system to perform more complex dependency checking than premake initially
     19	allows. This is done using the (currently) GCC toolchain to build generated
     20	C files which try to import certain headers, link to certain functions, link
     21	to certain libraries, or a combination of the above. It supports providing a
     22	custom source to try and build, link, and/or run per the implementation's
     23	choice, so the possibilities are nearly endless with that this system is
     24	capable of, though it could always do with more flexibility.
     25]]
     26
     27
     28local cxx = "gcc"
     29local cxx_flags = ""
     30local cxx_io_flags = "-o premakecheck.o -c premakecheck.c 2> /dev/null"
     31local cxx_includes = { }
     32
     33local link = "gcc"
     34local link_flags = ""
     35local link_io_flags = "-o premakecheck.out premakecheck.o"
     36local link_end = " 2> /dev/null"
     37
     38local run = "./premakecheck.out"
     39local run_flags = ""
     40local run_io_flags = " > ./premakecheck.stdout"
     41
     42local checked_printf = false
     43local has_printf = false
     44
     45-- Set the application used to compile the generated files.
     46function set_cxx(compiler)
     47	cxx = compiler
     48end
     49
     50-- Set custom flags for the compiler.
     51function set_cxx_flags(flags)
     52	cxx_flags = flags
     53end
     54
     55-- Include a search directory for libraries.
     56local function include_library_dir(dir)
     57	link_flags = link_flags .. "-L" .. dir .. " "
     58end
     59
     60-- Include a library to be linked durnig the link step.
     61local function link_library(lib)
     62	link_flags = link_flags .. "-l" .. lib .. " "
     63end
     64
     65-- Reset the link flags.
     66local function reset_link_flags()
     67	link_flags = ""
     68end
     69
     70-- Creates the build command line to be executed.
     71local function build_compile_line()
     72	return cxx .. " " .. cxx_flags .. " " .. cxx_io_flags
     73end
     74
     75-- Creates the link command line to be executed.
     76local function build_link_line()
     77	return link .. " " .. link_io_flags .. " " .. link_flags .. link_end
     78end
     79
     80-- Create the run line to be executed.
     81local function build_run_line()
     82	return run .. " " .. run_flags .. " " .. run_io_flags
     83end
     84
     85-- Builds a list of preprocessor include directives for all the include files
     86-- successfully found so far by these functions, so as to perform automatic
     87-- feature checking for the clientside code.
     88local function build_includes()
     89	local includes = ""
     90	for _,v in ipairs(cxx_includes) do
     91		includes = includes .. '#include "' .. v .. '"\n'
     92	end
     93	return includes
     94end
     95
     96-- Cleanup the generated build environment.
     97local function cleanup_build()
     98	os.remove("./premakecheck.c")
     99	os.remove("./premakecheck.o")
    100	os.remove("./premakecheck.out")
    101	os.remove("./premakecheck.stdout")
    102end
    103
    104-- Check if a source builds, links, and or/runs, where running depends on
    105-- linking and linking depends on building. The return from this function is
    106-- a triple, where the first is a boolean value indicating if it successfully
    107-- was built, the second is a boolean value indicating if it successfully
    108-- linked, and the third represents nil if it was not run or run correctly, or
    109-- the output from the program executed (may be empty for no output).
    110local function check_build_source(source, link, run)
    111	local file = fileopen("./premakecheck.c", "wt")
    112	file:write(source)
    113	file:close()
    114	local result = os.execute(build_compile_line())
    115	if not link then
    116		cleanup_build()
    117		if result == 0 then
    118			return true, false, nil -- compile, no link, no run
    119		end
    120		return false, false, nil -- no compile, no link, no run
    121	end
    122	-- try linking, too
    123	if result ~= 0 then
    124		-- can't link if it doesn't compile
    125		cleanup_build()
    126		return false, false, nil -- no compile, no link, no run
    127	end
    128	result = os.execute(build_link_line())
    129	if not run or result ~= 0 then -- have to link to run
    130		cleanup_build()
    131		return true, result == 0, nil -- compile, maybe link, no run
    132	end
    133	result = os.execute(build_run_line())
    134	local output = readfile("./premakecheck.stdout", "rt")
    135	cleanup_build()
    136	return true, true, output -- compile, link, ran
    137end
    138
    139-- Given C source code, determine whether the source code will compile in the
    140-- present environment. Returns true if the source was successfully compiled, or
    141-- false if otherwise.
    142function check_cxx_source_compiles(source)
    143	local r1, _, __ = check_build_source(source, false, false)
    144	return r1
    145end
    146
    147-- Given C source code, determine whether the source code can be built into a
    148-- working executable. That is, it will check if the code both compiles and
    149-- links. Returns true if the code was successfully built (compiled and linked),
    150-- or false if otherwise.
    151function check_cxx_source_builds(source)
    152	local r1, r2, _ = check_build_source(source, true, false)
    153	return r1 and r2
    154end
    155
    156-- Given C source code, attempt to compile, link, and execute the source code.
    157-- This function will return two values. The first is a boolean indicating
    158-- whether the source code was successfully run (meaning it was compiled, built,
    159-- and ran successfully), and the second value returned is the actual output
    160-- from running the application, or nil if it did not run correctly or was not
    161-- built. The output may be an empty string if the code does not print anything
    162-- to stdout.
    163function check_cxx_source_runs(source)
    164	local r1, r2, r3 = check_build_source(source, true, true)
    165	return r1 and r2 and (r3 ~= nil), r3
    166end
    167
    168-- Given a header file, check whether the header file is visible to the compiler
    169-- in the given environment. Returns a boolean indicating thus. If a header file
    170-- is found in either of these functions, it will be added to a list of headers
    171-- that can be used in subsequent dependency checks.
    172function check_include_file(inc)
    173	return check_include_files(inc)
    174end
    175
    176-- Given a variable list of header files, check whether all of the includes are
    177-- visible in the given environment. Every file must be included in order for
    178-- this function to return true.
    179function check_include_files(...)
    180	local source = ""
    181	for _, v in ipairs{...} do
    182		source = source .. '#include "' .. v .. '"\n'
    183	end
    184	local result = check_cxx_source_compiles(source)
    185	if result then
    186		for _, v in ipairs{...} do
    187			table.insert(cxx_includes, v)
    188		end
    189	end
    190	return result
    191end
    192
    193-- Given a directory, determine whether the directory contains any header files.
    194-- Unfortunately it does assume the extension is .h, but this can be altered in
    195-- future versions of this software. The function returns true if the directory
    196-- (or any of its subdirectories) contain .h files, or false if otherwise (such
    197-- as if the directory does not exist).
    198function check_include_directory(incDir)
    199	incDir = incDir:gsub("\\", "/"):gsub("//", "/")
    200	if incDir:sub(#incDir, #incDir) ~= "/" then
    201		incDir = incDir .. "/"
    202	end
    203	return #os.matchfiles(incDir .. "**.h") > 0
    204end
    205
    206-- Given a variable list of directories, iteratively check if each one contains
    207-- header files, per the functionality of check_include_directory. This function
    208-- returns true if and only if every listed directory or its subdirectories
    209-- contain .h files.
    210function check_include_directories(...)
    211	for _, v in ipairs{...} do
    212		if not check_include_directory(v) then
    213			return false
    214		end
    215	end
    216	return true
    217end
    218
    219-- Given a function name, attempt to determine whether the function can be found
    220-- within all of the known include files. Known include files are derived from
    221-- the check_include_file(s) functions.
    222function check_function_exists(func)
    223	local source = build_includes()
    224	source = source .. 'int main(int argc, char **argv) {\n'
    225	source = source .. '\tvoid *check = (void *) ' .. func .. ';\n'
    226	source = source .. '\treturn 0;\n'
    227	return check_cxx_source_builds(source .. '}')
    228end
    229
    230-- Given a library, a function that must exist within the library, and an
    231-- include file prototyping the function, this function determines whether those
    232-- three variables are able to build a working executable. That is, if a
    233-- function can be properly linked to using a given library, then the library
    234-- can be assumed to exist. Returns true if and only if the function was
    235-- correctly linked to.
    236function check_library_exists(lib, func, inc)
    237	local source = build_includes()
    238	if inc ~= nil then
    239		source = source .. '#include "' .. inc .. '"\n'
    240	end
    241	source = source .. 'int main(int argc, char **argv) {\n'
    242	source = source .. '\tvoid *check = (void *) ' .. func .. ';\n'
    243	source = source .. '\treturn 0;\n'
    244	if lib ~= nil then
    245		link_library(lib)
    246	end
    247	local result = check_cxx_source_builds(source .. '}')
    248	reset_link_flags()
    249	return result
    250end
    251
    252-- This is a merge variable list version of the check_library_exists function.
    253-- The thing to note with this function is that it will return true for the
    254-- first library found to correctly link to the function. This function is used
    255-- to determine whether the function is found in a list of libraries, not if it
    256-- is found in every one of the libraries.
    257function check_library_exists_multiple(func, inc, ...)
    258	for _,v in ipairs{...} do
    259		if check_library_exists(v, func, inc) then
    260			return true
    261		end
    262	end
    263	return false
    264end
    265
    266-- This is a wrapper for the check_library_exists function that will also
    267-- attempt to locate the library in question, in case it's not in a path the
    268-- compiler is already aware of. This function has the same return consequences
    269-- as check_library_exists.
    270function check_library_exists_lookup(lib, func, inc)
    271	local dir = os.findlib(lib)
    272	if dir == nil then
    273		return false
    274	end
    275	include_library_dir(dir)
    276	return check_library_exists(lib, func, inc)
    277end
    278
    279-- Given a valid C type name, this function generates a program that will print
    280-- the size of the type using the sizeof operator to the console, then parse the
    281-- size to indicate the byte size of the type on this platform. The resulting
    282-- executable is dependent on stdio and the printf function, which it safely
    283-- checks for behind the scenes. If these dependencies are not found for
    284-- whatever reason, this function returns 0, otherwise it returns a proper
    285-- numerical value representing the size of the specified type.
    286function check_type_size(typename)
    287	if not checked_printf then
    288		checked_printf = true
    289		has_printf = check_include_file("stdio.h") and check_function_exists("printf")
    290		if not has_printf then
    291			print("Warning: cannot check the size of a type without stdio and printf.")
    292		end
    293	end
    294	if not has_printf then
    295		return 0
    296	end
    297	local source = '#include "stdio.h"\n'
    298	source = source .. 'int main(int argc, char **argv) {\n'
    299	source = source .. '\tprintf("%d", sizeof(' .. typename .. '));\n'
    300	source = source .. '\treturn 0;\n'
    301	local success, result = check_cxx_source_runs(source .. '}');
    302	if not success then
    303		print("Warning: could not get the size of type: " .. typename)
    304		return 0
    305	end
    306	return tonumber(result)
    307end