premake/util/sdl_check_compile.lua
author Sam Lantinga
Thu, 01 Sep 2016 01:26:56 -0700
changeset 10304 ee83e0b4a36f
parent 9998 f67cf37e9cd4
child 10422 34fb2e531f7c
permissions -rwxr-xr-x
wayland: Add support for relative mouse mode, by Jonas Ã…dahl <jadahl@gmail.com>

Generate the C protocol files from the protocol XML files installed by
wayland-protocols, and use them to implement support for relative pointer
motions and pointer locking.

Note that at the time, the protocol is unstable and may change in the future.
Any future breaking changes will, however, fail gracefully and result in no
regressions compared to before this patch.
     1 -- Copyright (C) 1997-2016 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