123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- -- Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
- --
- -- This software is provided 'as-is', without any express or implied
- -- warranty. In no event will the authors be held liable for any damages
- -- arising from the use of this software.
- --
- -- Permission is granted to anyone to use this software for any purpose,
- -- including commercial applications, and to alter it and redistribute it
- -- freely.
- --
- -- Meta-build system using premake created and maintained by
- -- Benjamin Henning <b.henning@digipen.edu>
- --[[
- sdl_check_compile.lua
- This file provides various utility functions which allow the meta-build
- system to perform more complex dependency checking than premake initially
- allows. This is done using the (currently) GCC toolchain to build generated
- C files which try to import certain headers, link to certain functions, link
- to certain libraries, or a combination of the above. It supports providing a
- custom source to try and build, link, and/or run per the implementation's
- choice, so the possibilities are nearly endless with that this system is
- capable of, though it could always do with more flexibility.
- ]]
- local cxx = "gcc"
- local cxx_flags = ""
- local cxx_io_flags = "-o premakecheck.o -c premakecheck.c 2> /dev/null"
- local cxx_includes = { }
- local link = "gcc"
- local link_flags = ""
- local link_io_flags = "-o premakecheck.out premakecheck.o"
- local link_end = " 2> /dev/null"
- local run = "./premakecheck.out"
- local run_flags = ""
- local run_io_flags = " > ./premakecheck.stdout"
- local checked_printf = false
- local has_printf = false
- -- Set the application used to compile the generated files.
- function set_cxx(compiler)
- cxx = compiler
- end
- -- Set custom flags for the compiler.
- function set_cxx_flags(flags)
- cxx_flags = flags
- end
- -- Include a search directory for libraries.
- local function include_library_dir(dir)
- link_flags = link_flags .. "-L" .. dir .. " "
- end
- -- Include a library to be linked durnig the link step.
- local function link_library(lib)
- link_flags = link_flags .. "-l" .. lib .. " "
- end
- -- Reset the link flags.
- local function reset_link_flags()
- link_flags = ""
- end
- -- Creates the build command line to be executed.
- local function build_compile_line()
- return cxx .. " " .. cxx_flags .. " " .. cxx_io_flags
- end
- -- Creates the link command line to be executed.
- local function build_link_line()
- return link .. " " .. link_io_flags .. " " .. link_flags .. link_end
- end
- -- Create the run line to be executed.
- local function build_run_line()
- return run .. " " .. run_flags .. " " .. run_io_flags
- end
- -- Builds a list of preprocessor include directives for all the include files
- -- successfully found so far by these functions, so as to perform automatic
- -- feature checking for the clientside code.
- local function build_includes()
- local includes = ""
- for _,v in ipairs(cxx_includes) do
- includes = includes .. '#include "' .. v .. '"\n'
- end
- return includes
- end
- -- Cleanup the generated build environment.
- local function cleanup_build()
- os.remove("./premakecheck.c")
- os.remove("./premakecheck.o")
- os.remove("./premakecheck.out")
- os.remove("./premakecheck.stdout")
- end
- -- Check if a source builds, links, and or/runs, where running depends on
- -- linking and linking depends on building. The return from this function is
- -- a triple, where the first is a boolean value indicating if it successfully
- -- was built, the second is a boolean value indicating if it successfully
- -- linked, and the third represents nil if it was not run or run correctly, or
- -- the output from the program executed (may be empty for no output).
- local function check_build_source(source, link, run)
- local file = fileopen("./premakecheck.c", "wt")
- file:write(source)
- file:close()
- local result = os.execute(build_compile_line())
- if not link then
- cleanup_build()
- if result == 0 then
- return true, false, nil -- compile, no link, no run
- end
- return false, false, nil -- no compile, no link, no run
- end
- -- try linking, too
- if result ~= 0 then
- -- can't link if it doesn't compile
- cleanup_build()
- return false, false, nil -- no compile, no link, no run
- end
- result = os.execute(build_link_line())
- if not run or result ~= 0 then -- have to link to run
- cleanup_build()
- return true, result == 0, nil -- compile, maybe link, no run
- end
- result = os.execute(build_run_line())
- local output = readfile("./premakecheck.stdout", "rt")
- cleanup_build()
- return true, true, output -- compile, link, ran
- end
- -- Given C source code, determine whether the source code will compile in the
- -- present environment. Returns true if the source was successfully compiled, or
- -- false if otherwise.
- function check_cxx_source_compiles(source)
- local r1, _, __ = check_build_source(source, false, false)
- return r1
- end
- -- Given C source code, determine whether the source code can be built into a
- -- working executable. That is, it will check if the code both compiles and
- -- links. Returns true if the code was successfully built (compiled and linked),
- -- or false if otherwise.
- function check_cxx_source_builds(source)
- local r1, r2, _ = check_build_source(source, true, false)
- return r1 and r2
- end
- -- Given C source code, attempt to compile, link, and execute the source code.
- -- This function will return two values. The first is a boolean indicating
- -- whether the source code was successfully run (meaning it was compiled, built,
- -- and ran successfully), and the second value returned is the actual output
- -- from running the application, or nil if it did not run correctly or was not
- -- built. The output may be an empty string if the code does not print anything
- -- to stdout.
- function check_cxx_source_runs(source)
- local r1, r2, r3 = check_build_source(source, true, true)
- return r1 and r2 and (r3 ~= nil), r3
- end
- -- Given a header file, check whether the header file is visible to the compiler
- -- in the given environment. Returns a boolean indicating thus. If a header file
- -- is found in either of these functions, it will be added to a list of headers
- -- that can be used in subsequent dependency checks.
- function check_include_file(inc)
- return check_include_files(inc)
- end
- -- Given a variable list of header files, check whether all of the includes are
- -- visible in the given environment. Every file must be included in order for
- -- this function to return true.
- function check_include_files(...)
- local source = ""
- for _, v in ipairs{...} do
- source = source .. '#include "' .. v .. '"\n'
- end
- local result = check_cxx_source_compiles(source)
- if result then
- for _, v in ipairs{...} do
- table.insert(cxx_includes, v)
- end
- end
- return result
- end
- -- Given a directory, determine whether the directory contains any header files.
- -- Unfortunately it does assume the extension is .h, but this can be altered in
- -- future versions of this software. The function returns true if the directory
- -- (or any of its subdirectories) contain .h files, or false if otherwise (such
- -- as if the directory does not exist).
- function check_include_directory(incDir)
- incDir = incDir:gsub("\\", "/"):gsub("//", "/")
- if incDir:sub(#incDir, #incDir) ~= "/" then
- incDir = incDir .. "/"
- end
- return #os.matchfiles(incDir .. "**.h") > 0
- end
- -- Given a variable list of directories, iteratively check if each one contains
- -- header files, per the functionality of check_include_directory. This function
- -- returns true if and only if every listed directory or its subdirectories
- -- contain .h files.
- function check_include_directories(...)
- for _, v in ipairs{...} do
- if not check_include_directory(v) then
- return false
- end
- end
- return true
- end
- -- Given a function name, attempt to determine whether the function can be found
- -- within all of the known include files. Known include files are derived from
- -- the check_include_file(s) functions.
- function check_function_exists(func)
- local source = build_includes()
- source = source .. 'int main(int argc, char **argv) {\n'
- source = source .. '\tvoid *check = (void *) ' .. func .. ';\n'
- source = source .. '\treturn 0;\n'
- return check_cxx_source_builds(source .. '}')
- end
- -- Given a library, a function that must exist within the library, and an
- -- include file prototyping the function, this function determines whether those
- -- three variables are able to build a working executable. That is, if a
- -- function can be properly linked to using a given library, then the library
- -- can be assumed to exist. Returns true if and only if the function was
- -- correctly linked to.
- function check_library_exists(lib, func, inc)
- local source = build_includes()
- if inc ~= nil then
- source = source .. '#include "' .. inc .. '"\n'
- end
- source = source .. 'int main(int argc, char **argv) {\n'
- source = source .. '\tvoid *check = (void *) ' .. func .. ';\n'
- source = source .. '\treturn 0;\n'
- if lib ~= nil then
- link_library(lib)
- end
- local result = check_cxx_source_builds(source .. '}')
- reset_link_flags()
- return result
- end
- -- This is a merge variable list version of the check_library_exists function.
- -- The thing to note with this function is that it will return true for the
- -- first library found to correctly link to the function. This function is used
- -- to determine whether the function is found in a list of libraries, not if it
- -- is found in every one of the libraries.
- function check_library_exists_multiple(func, inc, ...)
- for _,v in ipairs{...} do
- if check_library_exists(v, func, inc) then
- return true
- end
- end
- return false
- end
- -- This is a wrapper for the check_library_exists function that will also
- -- attempt to locate the library in question, in case it's not in a path the
- -- compiler is already aware of. This function has the same return consequences
- -- as check_library_exists.
- function check_library_exists_lookup(lib, func, inc)
- local dir = os.findlib(lib)
- if dir == nil then
- return false
- end
- include_library_dir(dir)
- return check_library_exists(lib, func, inc)
- end
- -- Given a valid C type name, this function generates a program that will print
- -- the size of the type using the sizeof operator to the console, then parse the
- -- size to indicate the byte size of the type on this platform. The resulting
- -- executable is dependent on stdio and the printf function, which it safely
- -- checks for behind the scenes. If these dependencies are not found for
- -- whatever reason, this function returns 0, otherwise it returns a proper
- -- numerical value representing the size of the specified type.
- function check_type_size(typename)
- if not checked_printf then
- checked_printf = true
- has_printf = check_include_file("stdio.h") and check_function_exists("printf")
- if not has_printf then
- print("Warning: cannot check the size of a type without stdio and printf.")
- end
- end
- if not has_printf then
- return 0
- end
- local source = '#include "stdio.h"\n'
- source = source .. 'int main(int argc, char **argv) {\n'
- source = source .. '\tprintf("%d", sizeof(' .. typename .. '));\n'
- source = source .. '\treturn 0;\n'
- local success, result = check_cxx_source_runs(source .. '}');
- if not success then
- print("Warning: could not get the size of type: " .. typename)
- return 0
- end
- return tonumber(result)
- end
|