premake/util/sdl_check_compile.lua
author Ryan C. Gordon
Sun, 10 Nov 2013 00:38:37 -0500
changeset 7925 f090a47eb7f7
child 8149 681eb46b8ac4
permissions -rwxr-xr-x
Added Ben Henning's GSoC2013 work: premake build system.
     1 -- Copyright (C) 1997-2011 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 --[[
    15 sdl_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 
    28 local cxx = "gcc"
    29 local cxx_flags = ""
    30 local cxx_io_flags = "-o premakecheck.o -c premakecheck.c 2> /dev/null"
    31 local cxx_includes = { }
    32 
    33 local link = "gcc"
    34 local link_flags = ""
    35 local link_io_flags = "-o premakecheck.out premakecheck.o"
    36 local link_end = " 2> /dev/null"
    37 
    38 local run = "./premakecheck.out"
    39 local run_flags = ""
    40 local run_io_flags = " > ./premakecheck.stdout"
    41 
    42 local checked_printf = false
    43 local has_printf = false
    44 
    45 -- Set the application used to compile the generated files.
    46 function set_cxx(compiler)
    47 	cxx = compiler
    48 end
    49 
    50 -- Set custom flags for the compiler.
    51 function set_cxx_flags(flags)
    52 	cxx_flags = flags
    53 end
    54 
    55 -- Include a search directory for libraries.
    56 local function include_library_dir(dir)
    57 	link_flags = link_flags .. "-L" .. dir .. " "
    58 end
    59 
    60 -- Include a library to be linked durnig the link step.
    61 local function link_library(lib)
    62 	link_flags = link_flags .. "-l" .. lib .. " "
    63 end
    64 
    65 -- Reset the link flags.
    66 local function reset_link_flags()
    67 	link_flags = ""
    68 end
    69 
    70 -- Creates the build command line to be executed.
    71 local function build_compile_line()
    72 	return cxx .. " " .. cxx_flags .. " " .. cxx_io_flags
    73 end
    74 
    75 -- Creates the link command line to be executed.
    76 local function build_link_line()
    77 	return link .. " " .. link_io_flags .. " " .. link_flags .. link_end
    78 end
    79 
    80 -- Create the run line to be executed.
    81 local function build_run_line()
    82 	return run .. " " .. run_flags .. " " .. run_io_flags
    83 end
    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.
    88 local 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
    94 end
    95 
    96 -- Cleanup the generated build environment.
    97 local function cleanup_build()
    98 	os.remove("./premakecheck.c")
    99 	os.remove("./premakecheck.o")
   100 	os.remove("./premakecheck.out")
   101 	os.remove("./premakecheck.stdout")
   102 end
   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).
   110 local 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
   137 end
   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.
   142 function check_cxx_source_compiles(source)
   143 	local r1, _, __ = check_build_source(source, false, false)
   144 	return r1
   145 end
   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.
   151 function check_cxx_source_builds(source)
   152 	local r1, r2, _ = check_build_source(source, true, false)
   153 	return r1 and r2
   154 end
   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.
   163 function 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
   166 end
   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.
   172 function check_include_file(inc)
   173 	return check_include_files(inc)
   174 end
   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.
   179 function 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
   191 end
   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).
   198 function 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
   204 end
   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.
   210 function 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
   217 end
   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.
   222 function 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 .. '}')
   228 end
   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.
   236 function 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
   250 end
   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.
   257 function 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
   264 end
   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.
   270 function 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)
   277 end
   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.
   286 function 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)
   307 end