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