• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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--[[
15sdl_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
33projects = { }
34
35local currentProject = nil
36local currentDep = nil
37local nextFuncCompat = true -- by default, unless state otherwise changed
38local dependencyFunctions = { }
39local 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
43local function oscompat()
44	local compat = nextFuncCompat
45	nextFuncCompat = true
46	return compat
47end
48
49-- determine whether the specific OS name is within a pattern.
50local 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
58end
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.
75function SDL_registerDependencyChecker(name, func)
76	dependencyFunctions[name:lower()] = func
77end
78
79-- Initializes the definition of a SDL project given the name of the project.
80function 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
91end
92
93-- Specifies the build kind of the SDL project (e.g. StaticLib, SharedLib,
94-- ConsoleApp, etc.), based on premake presets.
95function SDL_kind(k)
96	if not oscompat() then return end
97	currentProject.kind = k
98end
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
106function 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
114end
115
116-- Specifies the programming language of the project, such as C or C++.
117function SDL_language(k)
118	if not oscompat() then return end
119	currentProject.language = k
120end
121
122-- Specifies the root directory in which the meta-build system should search for
123-- source files, given the paths and files added.
124function SDL_sourcedir(src)
125	if not oscompat() then return end
126	currentProject.sourcedir = src
127end
128
129-- Specifies the destination location of where the IDE files related to the
130-- project should be saved after generation.
131function SDL_projectLocation(loc)
132	if not oscompat() then return end
133	currentProject.projectLocation = loc
134end
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.
138function SDL_copy(tbl)
139	if not oscompat() then return end
140	currentProject.copy = tbl
141end
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.
147function SDL_projectDependencies(tbl)
148	if not oscompat() then return end
149	currentProject.projectDependencies = tbl
150end
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.
155function 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
163end
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.
169function 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)
174end
175
176-- Special function for getting the current OS. This factors in whether the
177-- metabuild system is in MinGW, Cygwin, or iOS mode.
178function 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()
187end
188
189-- Specifies which operating system this dependency targets, such as windows or
190-- macosx, as per premake presets.
191function 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
201end
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.
206function 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
216end
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")
223function SDL_isos(name)
224	nextFuncCompat = osmatch(SDL_getos(), name)
225end
226
227-- Same as SDL_isos, except it negates the internal state for exclusion
228-- checking.
229function SDL_isnotos(name)
230	nextFuncCompat = not osmatch(SDL_getos(), name)
231end
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.
236function SDL_is64bit()
237	nextFuncCompat = os.is64bit()
238end
239
240-- Same as SDL_is64bit, except it negates the internal state for
241-- exclusion checking.
242function SDL_isnot64bit()
243	nextFuncCompat = not os.is64bit()
244end
245
246-- Look at SDL_depfunc and SDL_notdepfunc for detailed information about this
247-- function.
248local 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
345end
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.
356function SDL_depfunc(funcname)
357	SDL_depfunc0(funcname, false)
358end
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).
364function SDL_notdepfunc(funcname)
365	SDL_depfunc0(funcname, true)
366end
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).
374function 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
387end
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.
392function 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
399end
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.
406function 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
415end
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.
423function 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
431end
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.
438function 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
446end
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.
453function 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
461end
462