premake/util/sdl_projects.lua
author Ryan C. Gordon
Mon, 04 Jan 2016 16:25:27 -0500
changeset 10006 5229da175b57
parent 9998 f67cf37e9cd4
permissions -rwxr-xr-x
x11: Support _NET_WM_USER_TIME and give _NET_ACTIVE_WINDOW a valid timestamp.

Fixes Bugzilla #3056.
     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_projects.lua
    16 
    17 	This file contains all the functions which are needed to define any project
    18 	within the meta-build system. Many of these functions serve as
    19 	pseudo-replacements for many similarly named premake functions, and that is
    20 	intentional. Even the implementation of these functions are intended to look
    21 	similar to regular premake code. These functions serve to dramatically
    22 	simplify the project definition process to just a few lines of code, versus
    23 	the many more needed for projects defined purely with premake.
    24 
    25 	This approach is possible because this meta-build system adds another layer of
    26 	indirection to the premake system, creating a sort of 'meta-meta-build'
    27 	system. Nevertheless, there is a lot more flexibility because the meta-build
    28 	system itself can be used to check for dependencies in a much more complex way
    29 	than premake originally intended. All of the functions useful to the project
    30 	definition system are contained in this file and are documented.
    31 ]]
    32 
    33 projects = { }
    34 
    35 local currentProject = nil
    36 local currentDep = nil
    37 local nextFuncCompat = true -- by default, unless state otherwise changed
    38 local dependencyFunctions = { }
    39 local dependencyResults = { } -- for when the dependencies are executed
    40 
    41 -- query whether this function is compatible; resets internal state of
    42 -- compatibility to true until SDL_isos is called again
    43 local function oscompat()
    44 	local compat = nextFuncCompat
    45 	nextFuncCompat = true
    46 	return compat
    47 end
    48 
    49 -- determine whether the specific OS name is within a pattern.
    50 local function osmatch(name, pattern)
    51 	local checks = pattern:explode('|')
    52 	for i,v in pairs(checks) do
    53 		if name == v then
    54 			return true
    55 		end
    56 	end
    57 	return false
    58 end
    59 
    60 -- Registers a dependency checker function based on a name. This function is
    61 -- used in order to determine compatibility with the current system for a given
    62 -- SDL_dependency. See SDL_depfunc for more information.
    63 --
    64 -- Specifies a function which will be invoked upon determining whether this
    65 -- dependency is valid for the current system setup (ie, whether the system
    66 -- has the right architecture, operating system, or even if it's installed).
    67 -- The dependency function takes no arguments, but it must return the following
    68 -- values:
    69 --
    70 --   <foundDep> [includePaths] [libPaths] [inputLibLibraries]
    71 --
    72 -- The last three are optional, unless foundDep is true. The name should be
    73 -- descriptive of the outside dependency, since it may be shown to the user.
    74 -- This function is intended to be used only after invoking SDL_dependency.
    75 function SDL_registerDependencyChecker(name, func)
    76 	dependencyFunctions[name:lower()] = func
    77 end
    78 
    79 -- Initializes the definition of a SDL project given the name of the project.
    80 function SDL_project(name)
    81 	if not oscompat() then return end
    82 	currentProject = { }
    83 	currentProject.name = name
    84 	currentProject.compat = true
    85 	projects[name] = currentProject
    86 	currentProject.dependencyTree = { }
    87 	-- stores which dependencies have already been checked on behalf of this
    88 	-- project
    89 	currentProject.dependencyValues = { }
    90 	currentDep = nil
    91 end
    92 
    93 -- Specifies the build kind of the SDL project (e.g. StaticLib, SharedLib,
    94 -- ConsoleApp, etc.), based on premake presets.
    95 function SDL_kind(k)
    96 	if not oscompat() then return end
    97 	currentProject.kind = k
    98 end
    99 
   100 -- Specifies which platforms this project supports. Note: this list is not the
   101 -- exact list of supported platforms in the generated project. The list of
   102 -- platforms this project supports will be the unique list of all combined
   103 -- projects for this SDL solution. Thus, only one project needs to actually
   104 -- maintain a list. This function is additive, that is, everytime it is called
   105 -- it adds it to a unique list of platforms
   106 function SDL_platforms(tbl)
   107 	if not oscompat() then return end
   108 	if not currentProject.platforms then
   109 		currentProject.platforms = { }
   110 	end
   111 	for k,v in pairs(tbl) do
   112 		currentProject.platforms[#currentProject.platforms + 1] = v
   113 	end
   114 end
   115 
   116 -- Specifies the programming language of the project, such as C or C++.
   117 function SDL_language(k)
   118 	if not oscompat() then return end
   119 	currentProject.language = k
   120 end
   121 
   122 -- Specifies the root directory in which the meta-build system should search for
   123 -- source files, given the paths and files added.
   124 function SDL_sourcedir(src)
   125 	if not oscompat() then return end
   126 	currentProject.sourcedir = src
   127 end
   128 
   129 -- Specifies the destination location of where the IDE files related to the
   130 -- project should be saved after generation.
   131 function SDL_projectLocation(loc)
   132 	if not oscompat() then return end
   133 	currentProject.projectLocation = loc
   134 end
   135 
   136 -- Specifies a table of files that should be copied from the source directory
   137 -- to the end result build directory of the binary file.
   138 function SDL_copy(tbl)
   139 	if not oscompat() then return end
   140 	currentProject.copy = tbl
   141 end
   142 
   143 -- Specifies a list of other SDL projects in this workspace the currently active
   144 -- project is dependent on. If the dependent project is a library, the binary
   145 -- result will be copied from its directory to the build directory of the
   146 -- currently active project automatically.
   147 function SDL_projectDependencies(tbl)
   148 	if not oscompat() then return end
   149 	currentProject.projectDependencies = tbl
   150 end
   151 
   152 -- Specifies a list of compiler-level preprocessor definitions that should be
   153 -- set in the resulting project upon compile time. This adds to the current
   154 -- table of defines.
   155 function SDL_defines(tbl)
   156 	if not oscompat() then return end
   157 	if not currentProject.defines then
   158 		currentProject.defines = { }
   159 	end
   160 	for k,v in pairs(tbl) do
   161 		currentProject.defines[#currentProject.defines + 1] = v
   162 	end
   163 end
   164 
   165 -- Initializes an outside dependency this project has, such as X11 or DirectX.
   166 -- This function, once invoked, may change the behavior of other SDL
   167 -- project-related functions, so be sure to be familiar with all the functions
   168 -- and any specified behavior when used around SDL_dependency.
   169 function SDL_dependency(name)
   170 	if not oscompat() then return end
   171 	currentDep = { nil, compat = true, }
   172 	currentDep.name = name
   173 	table.insert(currentProject.dependencyTree, currentDep)
   174 end
   175 
   176 -- Special function for getting the current OS. This factors in whether the
   177 -- metabuild system is in MinGW, Cygwin, or iOS mode.
   178 function SDL_getos()
   179 	if _OPTIONS["ios"] ~= nil then
   180 		return "ios"
   181 	elseif _OPTIONS["mingw"] ~= nil then
   182 		return "mingw"
   183 	elseif _OPTIONS["cygwin"] ~= nil then
   184 		return "cygwin"
   185 	end
   186 	return os.get()
   187 end
   188 
   189 -- Specifies which operating system this dependency targets, such as windows or
   190 -- macosx, as per premake presets.
   191 function SDL_os(name)
   192 	if not oscompat() then return end
   193 	if not currentProject then return end
   194 	if not currentDep then
   195 		currentProject.opsys = name
   196 		currentProject.compat = osmatch(SDL_getos(), name)
   197 	else
   198 		currentDep.opsys = name
   199 		currentDep.compat = osmatch(SDL_getos(), name)
   200 	end
   201 end
   202 
   203 -- Specifies which operating system this dependency does not targets. This is
   204 -- for nearly platform-independent projects or dependencies that will not work
   205 -- on specific systems, such as ios.
   206 function SDL_notos(name)
   207 	if not oscompat() then return end
   208 	if not currentProject then return end
   209 	if not currentDep then
   210 		currentProject.opsys = "~" .. name
   211 		currentProject.compat = not osmatch(SDL_getos(), name)
   212 	else
   213 		currentDep.opsys = "~" .. name
   214 		currentDep.compat = not osmatch(SDL_getos(), name)
   215 	end
   216 end
   217 
   218 -- Changes the internal state of function compatibility based on whether the
   219 -- current os is the one expected; the next function will be affected by this
   220 -- change, but no others. The name can be a pattern using '|' to separate
   221 -- multiple operating systems, such as:
   222 --   SDL_isos("windows|macosx")
   223 function SDL_isos(name)
   224 	nextFuncCompat = osmatch(SDL_getos(), name)
   225 end
   226 
   227 -- Same as SDL_isos, except it negates the internal state for exclusion
   228 -- checking.
   229 function SDL_isnotos(name)
   230 	nextFuncCompat = not osmatch(SDL_getos(), name)
   231 end
   232 
   233 -- Changes the internal state of function compatibility based on whether the
   234 -- current system is running a 64bit Operating System and architecture; the
   235 -- next function will be affected by this change, but none thereafter.
   236 function SDL_is64bit()
   237 	nextFuncCompat = os.is64bit()
   238 end
   239 
   240 -- Same as SDL_is64bit, except it negates the internal state for
   241 -- exclusion checking.
   242 function SDL_isnot64bit()
   243 	nextFuncCompat = not os.is64bit()
   244 end
   245 
   246 -- Look at SDL_depfunc and SDL_notdepfunc for detailed information about this
   247 -- function.
   248 local function SDL_depfunc0(funcname, exclude)
   249 	if not oscompat() then return end
   250 	if not currentDep.compat then return end
   251 	local force = _OPTIONS[funcname:lower()] ~= nil
   252 	local func = dependencyFunctions[funcname:lower()]
   253 	if not func then
   254 		print("Warning: could not find dependency function named: " .. funcname)
   255 		currentDep.compat = false
   256 		return
   257 	end
   258 	local cachedFuncResults = dependencyResults[funcname:lower()]
   259 	local depFound, depInc, depLib, depInput
   260 	if cachedFuncResults then
   261 		depFound = cachedFuncResults.depFound
   262 		-- just skip the rest of the function, the user was already warned
   263 		-- exclude mode varies the compatibility slightly
   264 		if force then
   265 			depFound = true
   266 		end
   267 		if not depFound and not exclude then
   268 			currentDep.compat = false
   269 			return
   270 		elseif depFound and exclude then
   271 			currentDep.compat = false
   272 			return
   273 		end
   274 		depInc = cachedFuncResults.depInc
   275 		depLib = cachedFuncResults.depLib
   276 		depInput = cachedFuncResults.depInput
   277 	else
   278 		local result = func()
   279 		if result.found then
   280 			depFound = result.found
   281 		else
   282 			depFound = false
   283 		end
   284 		if force then
   285 			depFound = true
   286 		end
   287 		if result.incDirs then
   288 			depInc = result.incDirs
   289 		else
   290 			depInc = { }
   291 		end
   292 		if result.libDirs then
   293 			depLib = result.libDirs
   294 		else
   295 			depLib = { }
   296 		end
   297 		if result.libs then
   298 			depInput = result.libs
   299 		else
   300 			depInput = { }
   301 		end
   302 		cachedFuncResults = { }
   303 		cachedFuncResults.depFound = depFound
   304 		cachedFuncResults.depInc = depInc
   305 		cachedFuncResults.depLib = depLib
   306 		cachedFuncResults.depInput = depInput
   307 		dependencyResults[funcname:lower()] = cachedFuncResults
   308 		if not depFound and not exclude then
   309 			currentDep.compat = false
   310 			return
   311 		elseif depFound and exclude then
   312 			currentDep.compat = false
   313 			return
   314 		end
   315 	end
   316 	-- we only want to embed this dependency if we're not in exclude mode
   317 	if depFound and not exclude then
   318 		local dependency = { }
   319 		if not currentDep.includes then
   320 			currentDep.includes = { }
   321 		end
   322 		for k,v in pairs(depInc) do
   323 			currentDep.includes[v] = v
   324 		end
   325 		if not currentDep.libs then
   326 			currentDep.libs = { }
   327 		end
   328 		for k,v in pairs(depLib) do
   329 			currentDep.libs[v] = v
   330 		end
   331 		if not currentDep.links then
   332 			currentDep.links = { }
   333 		end
   334 		for k,v in pairs(depInput) do
   335 			currentDep.links[v] = v
   336 		end
   337 	else -- end of dependency found check
   338 		-- if we are not excluding this dependency, then print a warning
   339 		-- if not found
   340 		if not exclude then
   341 			print("Warning: could not find dependency: " .. funcname)
   342 		end
   343 		currentDep.compat = exclude
   344 	end
   345 end
   346 
   347 -- Given a dependency name, this function will register the dependency and try
   348 -- to pair it with a dependency function that was registered through
   349 -- SDL_registerDependencyChecker. If the function is not found, compatibility
   350 -- will automatically be dropped for this project and a warning will be printed
   351 -- to the standard output. Otherwise, the dependency function will be invoked
   352 -- and compatibility for the project will be updated. If the project currently
   353 -- is not compatible based on the Operating System or previous dependency, the
   354 -- dependency function will not be checked at all and this function will
   355 -- silently return.
   356 function SDL_depfunc(funcname)
   357 	SDL_depfunc0(funcname, false)
   358 end
   359 
   360 -- Same as SDL_depfunc, except this forces dependency on the function failing,
   361 -- rather than succeeding. This is useful for situations where two different
   362 -- files are required based on whether a dependency is found (such as the
   363 -- joystick and haptic systems).
   364 function SDL_notdepfunc(funcname)
   365 	SDL_depfunc0(funcname, true)
   366 end
   367 
   368 -- Determines whether the specified dependency is supported without actually
   369 -- executing the dependency or changing the internal states of the current
   370 -- project or dependency definition. This function will only work if the
   371 -- dependency has already been checked and its results cached within the
   372 -- definition system. This function returns true if the dependency is known to
   373 -- be supported, or false if otherwise (or if it cannot be known at this time).
   374 function SDL_assertdepfunc(funcname)
   375 	-- if forced, then of course it's on
   376 	if _OPTIONS[funcname:lower()] then
   377 		return true
   378 	end
   379 	local results = dependencyResults[funcname:lower()]
   380 	if not results or not results.depFound then
   381 		-- either not excuted yet, doesn't exist, or wasn't found
   382 		print("Warning: required dependency not found: " .. funcname ..
   383 			". Make sure your dependencies are in a logical order.")
   384 		return false
   385 	end
   386 	return true
   387 end
   388 
   389 -- Returns a list of currently registered dependencies. The values within the
   390 -- table will be sorted, but their names will be lowercased due to internal
   391 -- handling of case-insensitive dependency names.
   392 function SDL_getDependencies()
   393 	local deps = { }
   394 	for k,_ in pairs(dependencyFunctions) do
   395 		deps[#deps + 1] = k
   396 	end
   397 	table.sort(deps)
   398 	return deps
   399 end
   400 
   401 -- Specifies a list of libraries that should always be linked to in this
   402 -- project, regardless of a dependency function. If after a dependency
   403 -- declaration, these files will only be included in the project if the
   404 -- dependency is compatible with the native system, given SDL_os usage and any
   405 -- sort of custom dependency function.
   406 function SDL_links(tbl)
   407 	if not oscompat() then return end
   408 	if currentDep and not currentDep.compat then return end
   409 	if currentProject.customLinks == nil then
   410 		currentProject.customLinks = { }
   411 	end
   412 	for i,v in ipairs(tbl) do
   413 		currentProject.customLinks[#currentProject.customLinks + 1] = v
   414 	end
   415 end
   416 
   417 -- Specifies a list of configuration values that are assigned as preprocessor
   418 -- definitions in the SDL configuration header, used to globally configure
   419 -- features during the building of the SDL library. If after a dependency
   420 -- declaration, these files will only be included in the project if the
   421 -- dependency is compatible with the native system, given SDL_os usage and any
   422 -- sort of custom dependency function.
   423 function SDL_config(tbl)
   424 	if not oscompat() then return end
   425 	if not currentDep then
   426 		currentProject.config = tbl
   427 		return
   428 	end
   429 	if not currentDep.compat then return end
   430 	currentDep.config = tbl
   431 end
   432 
   433 -- Specifies a list of paths where all .c, .h, and .m files should be included
   434 -- for compiling, where the source directory is the root. If after a dependency
   435 -- declaration, these files will only be included in the project if the
   436 -- dependency is compatible with the native system, given SDL_os usage and any
   437 -- sort of custom dependency function.
   438 function SDL_paths(tbl)
   439 	if not oscompat() then return end
   440 	if not currentDep then
   441 		currentProject.paths = tbl
   442 		return
   443 	end
   444 	if not currentDep.compat then return end
   445 	currentDep.paths = tbl
   446 end
   447 
   448 -- Specifies a list of files found within the source directory that this project
   449 -- should include during compile time. If after a dependency declaration, these
   450 -- files will only be included in the project if the dependency is compatible
   451 -- with the native system, given SDL_os usage and any sort of custom dependency
   452 -- function.
   453 function SDL_files(tbl)
   454 	if not oscompat() then return end
   455 	if not currentDep then
   456 		currentProject.files = tbl
   457 		return
   458 	end
   459 	if not currentDep.compat then return end
   460 	currentDep.files = tbl
   461 end