diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 66bda3cd..00000000 --- a/.gitmodules +++ /dev/null @@ -1,15 +0,0 @@ -[submodule "modules/xcode"] - path = modules/xcode - url = https://github.com/premake/premake-xcode.git -[submodule "modules/monodevelop"] - path = modules/monodevelop - url = https://github.com/premake/premake-monodevelop.git -[submodule "modules/codelite"] - path = modules/codelite - url = https://github.com/premake/premake-codelite.git -[submodule "modules/d"] - path = modules/d - url = https://github.com/premake/premake-dlang.git -[submodule "modules/raw"] - path = modules/raw - url = https://github.com/premake/premake-raw.git diff --git a/CHANGES.txt b/CHANGES.txt index 8817a400..ecd7c920 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,6 +5,14 @@ See https://github.com/premake/premake-core/wiki/What's-New-in-5.0 for the complete list of changes from the Premake 4.x series. +Since 5.0-alpha9: + +* New: `symbols()`, replaces and extends flags {"Symbols"} +* New: `symbolspath()` to specify location of symbol database +* New: `table.shallowcopy()` +* New: `vectorextensions` value "IA32" +* Fix: --start-group/--end-group now only enclose project libraries + Since 5.0-alpha8: * New: `buildcustomizations()` imports custom .props files for VS diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 7416ef07..a2fa379c 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -23,6 +23,8 @@ Patch contributors: Damien Courtois * module loading fixes * bug fixes + David Ely + * symbols() API and flag deprecation Gabi Davar * added file.directory to token environment João Matos (joao@tritao.eu) @@ -37,6 +39,8 @@ Patch contributors: * path.join() fixes Mark Chandler * prevent self-linking + Matthew Endsley + * File matching improvements Mark Sararu * Makefile bug fixes Mihai Sebea diff --git a/README.md b/README.md index c312b4e1..7a341a52 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PREMAKE 5 (core) -* Linux : [![Build Status](https://travis-ci.org/premake/premake-core.svg?branch=master)](https://travis-ci.org/premake/premake-core) -* Windows: [![Build status](https://ci.appveyor.com/api/projects/status/lc9g332y2lqvel8h?svg=true)](https://ci.appveyor.com/project/PremakeOrganization/premake-core) + [![Build Status](https://travis-ci.org/premake/premake-core.svg?branch=master)](https://travis-ci.org/premake/premake-core) + [![Build status](https://ci.appveyor.com/api/projects/status/lc9g332y2lqvel8h?svg=true)](https://ci.appveyor.com/project/PremakeOrganization/premake-core) diff --git a/modules/codelite b/modules/codelite deleted file mode 160000 index c72dbdf9..00000000 --- a/modules/codelite +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c72dbdf9e0db9f6673410ef07cad1e5e8fcbefaf diff --git a/modules/codelite/README.md b/modules/codelite/README.md new file mode 100644 index 00000000..757a91fd --- /dev/null +++ b/modules/codelite/README.md @@ -0,0 +1,13 @@ +Premake extension to support the [CodeLite](http://www.codelite.org/) IDE + +### Features ### + +* Support for C/C++ language projects + +### Usage ### + +Simply generate your project using the `codelite` action: +```bash +premake5 codelite +``` +and open the generated project file in CodeLite. diff --git a/modules/codelite/_manifest.lua b/modules/codelite/_manifest.lua new file mode 100644 index 00000000..02efd902 --- /dev/null +++ b/modules/codelite/_manifest.lua @@ -0,0 +1,6 @@ +return { + "_preload.lua", + "codelite.lua", + "codelite_workspace.lua", + "codelite_project.lua", +} diff --git a/modules/codelite/_preload.lua b/modules/codelite/_preload.lua new file mode 100644 index 00000000..d7accaae --- /dev/null +++ b/modules/codelite/_preload.lua @@ -0,0 +1,57 @@ +-- +-- Name: codelite/_preload.lua +-- Purpose: Define the CodeLite action. +-- Author: Ryan Pusztai +-- Modified by: Andrea Zanellato +-- Andrew Gough +-- Manu Evans +-- Created: 2013/05/06 +-- Copyright: (c) 2008-2015 Jason Perkins and the Premake project +-- + + local p = premake + + newaction + { + -- Metadata for the command line and help system + + trigger = "codelite", + shortname = "CodeLite", + description = "Generate CodeLite project files", + + -- The capabilities of this action + + valid_kinds = { "ConsoleApp", "WindowedApp", "Makefile", "SharedLib", "StaticLib", "Utility" }, + valid_languages = { "C", "C++" }, + valid_tools = { + cc = { "gcc", "clang", "msc" } + }, + + -- Workspace and project generation logic + + onWorkspace = function(wks) + p.modules.codelite.generateWorkspace(wks) + end, + onProject = function(prj) + p.modules.codelite.generateProject(prj) + end, + + onCleanWorkspace = function(wks) + p.modules.codelite.cleanWorkspace(wks) + end, + onCleanProject = function(prj) + p.modules.codelite.cleanProject(prj) + end, + onCleanTarget = function(prj) + p.modules.codelite.cleanTarget(prj) + end, + } + + +-- +-- Decide when the full module should be loaded. +-- + + return function(cfg) + return (_ACTION == "codelite") + end diff --git a/modules/codelite/codelite.lua b/modules/codelite/codelite.lua new file mode 100755 index 00000000..ea1be19e --- /dev/null +++ b/modules/codelite/codelite.lua @@ -0,0 +1,75 @@ +-- +-- Name: codelite/codelite.lua +-- Purpose: Define the CodeLite action(s). +-- Author: Ryan Pusztai +-- Modified by: Andrea Zanellato +-- Andrew Gough +-- Manu Evans +-- Created: 2013/05/06 +-- Copyright: (c) 2008-2015 Jason Perkins and the Premake project +-- + + local p = premake + + p.modules.codelite = {} + p.modules.codelite._VERSION = p._VERSION + + local codelite = p.modules.codelite + local project = p.project + + + function codelite.cfgname(cfg) + local cfgname = cfg.buildcfg + if codelite.workspace.multiplePlatforms then + cfgname = string.format("%s|%s", cfg.platform, cfg.buildcfg) + end + return cfgname + end + + function codelite.esc(value) + local result = value:gsub('"', '\\"') + result = result:gsub('<', '<') + result = result:gsub('>', '>') + return result + end + + function codelite.generateWorkspace(wks) + p.eol("\r\n") + p.indent(" ") + p.escaper(codelite.esc) + + p.generate(wks, ".workspace", codelite.workspace.generate) + end + + function codelite.generateProject(prj) + p.eol("\r\n") + p.indent(" ") + p.escaper(codelite.esc) + + if project.iscpp(prj) then + p.generate(prj, ".project", codelite.project.generate) + end + end + + function codelite.cleanWorkspace(wks) + p.clean.file(wks, wks.name .. ".workspace") + p.clean.file(wks, wks.name .. "_wsp.mk") + p.clean.file(wks, wks.name .. ".tags") + p.clean.file(wks, ".clang") + end + + function codelite.cleanProject(prj) + p.clean.file(prj, prj.name .. ".project") + p.clean.file(prj, prj.name .. ".mk") + p.clean.file(prj, prj.name .. ".list") + p.clean.file(prj, prj.name .. ".out") + end + + function codelite.cleanTarget(prj) + -- TODO.. + end + + include("codelite_workspace.lua") + include("codelite_project.lua") + + return codelite diff --git a/modules/codelite/codelite_project.lua b/modules/codelite/codelite_project.lua new file mode 100755 index 00000000..b1bc9de5 --- /dev/null +++ b/modules/codelite/codelite_project.lua @@ -0,0 +1,455 @@ +-- +-- Name: codelite/codelite_project.lua +-- Purpose: Generate a CodeLite C/C++ project file. +-- Author: Ryan Pusztai +-- Modified by: Andrea Zanellato +-- Manu Evans +-- Created: 2013/05/06 +-- Copyright: (c) 2008-2015 Jason Perkins and the Premake project +-- + + local p = premake + local tree = p.tree + local project = p.project + local config = p.config + local codelite = p.modules.codelite + + codelite.project = {} + local m = codelite.project + + + function codelite.getLinks(cfg) + -- System libraries are undecorated, add the required extension + return config.getlinks(cfg, "system", "fullpath") + end + + function codelite.getSiblingLinks(cfg) + -- If we need sibling projects to be listed explicitly, add them on + return config.getlinks(cfg, "siblings", "fullpath") + end + + + m.elements = {} + + m.ctools = { + gcc = "gnu gcc", + clang = "clang", + msc = "Visual C++", + } + m.cxxtools = { + gcc = "gnu g++", + clang = "clang++", + msc = "Visual C++", + } + + function m.getcompilername(cfg) + local tool = _OPTIONS.cc or cfg.toolset or p.CLANG + + local toolset = p.tools[tool] + if not toolset then + error("Invalid toolset '" + (_OPTIONS.cc or cfg.toolset) + "'") + end + + if cfg.language == "C" then + return m.ctools[tool] + elseif cfg.language == "C++" then + return m.cxxtools[tool] + end + end + + function m.getcompiler(cfg) + local toolset = p.tools[_OPTIONS.cc or cfg.toolset or p.CLANG] + if not toolset then + error("Invalid toolset '" + (_OPTIONS.cc or cfg.toolset) + "'") + end + return toolset + end + + local function configuration_iscustombuild(cfg) + + return cfg and (cfg.kind == p.MAKEFILE) and (#cfg.buildcommands > 0) + end + + local function configuration_isfilelist(cfg) + + return cfg and (cfg.buildaction == "None") and not configuration_iscustombuild(cfg) + end + + local function configuration_needresoptions(cfg) + + return cfg and config.findfile(cfg, ".rc") and not configuration_iscustombuild(cfg) + end + + + m.internalTypeMap = { + ConsoleApp = "Console", + WindowedApp = "Console", + Makefile = "", + SharedLib = "Library", + StaticLib = "Library" + } + + function m.header(prj) + _p('') + + local type = m.internalTypeMap[prj.kind] or "" + _x('', prj.name, type) + end + + function m.plugins(prj) +-- _p(1, '') + -- + -- +-- _p(1, '') + + _p(1, '') + end + + function m.description(prj) + _p(1, '') + + -- TODO: ... + end + + function m.files(prj) + local tr = project.getsourcetree(prj) + tree.traverse(tr, { + -- folders are handled at the internal nodes + onbranchenter = function(node, depth) + _p(depth, '', node.name) + end, + onbranchexit = function(node, depth) + _p(depth, '') + end, + -- source files are handled at the leaves + onleaf = function(node, depth) + + local excludesFromBuild = {} + for cfg in project.eachconfig(prj) do + local cfgname = codelite.cfgname(cfg) + local fcfg = p.fileconfig.getconfig(node, cfg) + if not fcfg or fcfg.flags.ExcludeFromBuild then + table.insert(excludesFromBuild, cfgname) + end + end + + if #excludesFromBuild > 0 then + _p(depth, '', node.relpath, table.concat(excludesFromBuild, ';')) + else + _p(depth, '', node.relpath) + end + end, + }, false, 1) + end + + function m.dependencies(prj) + + -- TODO: dependencies don't emit a line for each config if there aren't any... + +-- _p(1, '') + + local dependencies = project.getdependencies(prj) + for cfg in project.eachconfig(prj) do + cfgname = codelite.cfgname(cfg) + if #dependencies > 0 then + _p(1, '', cfgname) + for _, dependency in ipairs(dependencies) do + _p(2, '', dependency.name) + end + _p(1, '') + else + _p(1, '', cfgname) + end + end + end + + + function m.global_compiler(prj) + _p(3, '') + _p(4, '') + _p(3, '') + end + + function m.global_linker(prj) + _p(3, '') + _p(4, '') + _p(3, '') + end + + function m.global_resourceCompiler(prj) + _p(3, '') + end + + m.elements.globalSettings = function(prj) + return { + m.global_compiler, + m.global_linker, + m.global_resourceCompiler, + } + end + + + function m.compiler(cfg) + if configuration_iscustombuild(cfg) or configuration_isfilelist(cfg) then + _p(3, '') + return + end + + local toolset = m.getcompiler(cfg) + local cxxflags = table.concat(table.join(toolset.getcflags(cfg), toolset.getcxxflags(cfg), cfg.buildoptions), ";") + local cflags = table.concat(table.join(toolset.getcflags(cfg), cfg.buildoptions), ";") + local asmflags = "" + local pch = "" + + _x(3, '', cxxflags, cflags, asmflags, pch) + + for _, includedir in ipairs(cfg.includedirs) do + _x(4, '', project.getrelative(cfg.project, includedir)) + end + for _, define in ipairs(cfg.defines) do + _x(4, '', p.esc(define)) + end + _p(3, '') + end + + function m.linker(cfg) + if configuration_iscustombuild(cfg) or configuration_isfilelist(cfg) then + _p(3, '') + return + end + + local toolset = m.getcompiler(cfg) + local flags = table.join(toolset.getldflags(cfg), cfg.linkoptions) + local withdeps = table.join(flags, codelite.getSiblingLinks(cfg)) + local ldflags = table.concat(withdeps, ";") + + _x(3, '', ldflags) + + if #cfg.libdirs > 0 then + local libdirs = project.getrelative(cfg.project, cfg.libdirs) + for _, libpath in ipairs(libdirs) do + _x(4, '', libpath) + end + end + + local links = codelite.getLinks(cfg) + for _, libname in ipairs(links) do + _x(4, '', libname) + end + _p(3, '') + end + + function m.resourceCompiler(cfg) + if not configuration_needresoptions(cfg) then + _p(3, '') + return + end + + local toolset = m.getcompiler(cfg) + local defines = table.implode(toolset.getdefines(table.join(cfg.defines, cfg.resdefines)), "", ";", "") + local options = table.concat(cfg.resoptions, ";") + + _x(3, '', defines, options) + for _, includepath in ipairs(table.join(cfg.includedirs, cfg.resincludedirs)) do + _x(4, '', project.getrelative(cfg.project, includepath)) + end + _p(3, '') + end + + function m.general(cfg) + if configuration_isfilelist(cfg) then + _p(3, '') + return + end + + local prj = cfg.project + + local isExe = prj.kind == "WindowedApp" or prj.kind == "ConsoleApp" + local targetpath = project.getrelative(prj, cfg.buildtarget.directory) + local objdir = project.getrelative(prj, cfg.objdir) + local targetname = project.getrelative(prj, cfg.buildtarget.abspath) + local command = iif(isExe, targetname, "") + local cmdargs = iif(isExe, table.concat(cfg.debugargs, " "), "") -- TODO: should this be debugargs instead? + local useseparatedebugargs = "no" + local debugargs = "" + local workingdir = iif(isExe, project.getrelative(prj, cfg.debugdir), "") + local pauseexec = iif(prj.kind == "ConsoleApp", "yes", "no") + local isguiprogram = iif(prj.kind == "WindowedApp", "yes", "no") + local isenabled = iif(cfg.flags.ExcludeFromBuild, "no", "yes") + + _x(3, '', + targetname, objdir, command, cmdargs, useseparatedebugargs, debugargs, workingdir, pauseexec, isguiprogram, isenabled) + end + + function m.environment(cfg) + _p(3, '') + local variables = "" + _x(4, '', variables) + _p(3, '') + end + + function m.debugger(cfg) + + _p(3, '', iif(cfg.debugremotehost, "yes", "no"), cfg.debugremotehost or "", iif(cfg.debugport, tostring(cfg.debugport), ""), iif(cfg.debugextendedprotocol, "yes", "no")) + if #cfg.debugsearchpaths > 0 then + _p(4, '%s', table.concat(premake.esc(project.getrelative(cfg.project, cfg.debugsearchpaths)), "\n")) + else + _p(4, '') + end + if #cfg.debugconnectcommands > 0 then + _p(4, '%s', table.concat(premake.esc(cfg.debugconnectcommands), "\n")) + else + _p(4, '') + end + if #cfg.debugstartupcommands > 0 then + _p(4, '%s', table.concat(premake.esc(cfg.debugstartupcommands), "\n")) + else + _p(4, '') + end + _p(3, '') + end + + function m.preBuild(cfg) + if #cfg.prebuildcommands > 0 then + _p(3, '') + for _, commands in ipairs(cfg.prebuildcommands) do + _x(4, '%s', + p.esc(commands)) + end + _p(3, '') + end + end + + function m.postBuild(cfg) + if #cfg.postbuildcommands > 0 then + _p(3, '') + for _, commands in ipairs(cfg.postbuildcommands) do + _x(4, '%s', + p.esc(commands)) + end + _p(3, '') + end + end + + function m.customBuild(cfg) + if not configuration_iscustombuild(cfg) then + _p(3, '') + return + end + + local build = table.implode(cfg.buildcommands,"","","") + local clean = table.implode(cfg.cleancommands,"","","") + local rebuild = table.implode(cfg.rebuildcommands,"","","") + + _p(3, '') + _x(4, '%s', build) + _x(4, '%s', clean) + _x(4, '%s', rebuild) + _p(4, '') + _p(4, '') + _p(4, '') + _p(4, '') + _p(4, '') + _p(3, '') + end + + function m.additionalRules(cfg) + if configuration_iscustombuild(cfg) then + _p(3, '') + return + end + + _p(3, '') + _p(4, '') + _p(4, '') + _p(3, '') + end + + function m.completion(cfg) + _p(3, '', iif(cfg.flags["C++11"], "yes", "no"), iif(cfg.flags["C++14"], "yes", "no")) + _p(4, '') + _p(4, '') + _p(4, '') -- TODO: we might want to set special code completion macros...? + _p(4, '') -- TODO: search paths for code completion? + _p(3, '') + end + + m.elements.settings = function(cfg) + return { + m.compiler, + m.linker, + m.resourceCompiler, + m.general, + m.environment, + m.debugger, + m.preBuild, + m.postBuild, + m.customBuild, + m.additionalRules, + m.completion, + } + end + + m.types = + { + ConsoleApp = "Executable", + Makefile = "", + SharedLib = "Dynamic Library", + StaticLib = "Static Library", + WindowedApp = "Executable", + Utility = "", + } + + m.debuggers = + { + Default = "GNU gdb debugger", + GDB = "GNU gdb debugger", + LLDB = "LLDB Debugger", + } + + function m.settings(prj) + _p(1, '', m.types[prj.kind] or "") + + _p(2, '') + p.callArray(m.elements.globalSettings, prj) + _p(2, '') + + for cfg in project.eachconfig(prj) do + + local cfgname = codelite.cfgname(cfg) + local compiler = m.getcompilername(cfg) + local debugger = m.debuggers[cfg.debugger] or m.debuggers.Default + local type = m.types[cfg.kind] + + _x(2, '', cfgname, compiler, debugger, type) + + p.callArray(m.elements.settings, cfg) + + _p(2, '') + end + + _p(1, '') + end + + + m.elements.project = function(prj) + return { + m.header, + m.plugins, + m.description, + m.files, + m.dependencies, + m.settings, + } + end + +-- +-- Project: Generate the CodeLite project file. +-- + function m.generate(prj) + p.utf8() + + p.callArray(m.elements.project, prj) + + _p('') + end diff --git a/modules/codelite/codelite_workspace.lua b/modules/codelite/codelite_workspace.lua new file mode 100755 index 00000000..6ab4697f --- /dev/null +++ b/modules/codelite/codelite_workspace.lua @@ -0,0 +1,97 @@ +-- +-- Name: codelite/codelite_workspace.lua +-- Purpose: Generate a CodeLite workspace. +-- Author: Ryan Pusztai +-- Modified by: Andrea Zanellato +-- Manu Evans +-- Created: 2013/05/06 +-- Copyright: (c) 2008-2015 Jason Perkins and the Premake project +-- + + local p = premake + local project = p.project + local workspace = p.workspace + local tree = p.tree + local codelite = p.modules.codelite + + codelite.workspace = {} + local m = codelite.workspace + +-- +-- Generate a CodeLite workspace +-- + function m.generate(wks) + p.utf8() + + -- + -- Header + -- + _p('') + + local tagsdb = "" +-- local tagsdb = "./" .. wks.name .. ".tags" + _p('', wks.name, tagsdb) + + -- + -- Project list + -- + local tr = workspace.grouptree(wks) + tree.traverse(tr, { + onleaf = function(n) + local prj = n.project + + -- Build a relative path from the workspace file to the project file + local prjpath = p.filename(prj, ".project") + prjpath = path.getrelative(prj.workspace.location, prjpath) + + local active = iif(prj.name == wks.startproject, ' Active="Yes"', '') + _x(1, '', prj.name, prjpath, active) + end, + + onbranch = function(n) + -- TODO: not sure what situation this appears...? + -- premake5.lua emit's one of these for 'contrib', which is a top-level folder with the zip projects + end, + }) + + -- + -- Configurations + -- + + -- count the number of platforms + local platformsPresent = {} + local numPlatforms = 0 + + for cfg in workspace.eachconfig(wks) do + local platform = cfg.platform + if platform and not platformsPresent[platform] then + numPlatforms = numPlatforms + 1 + platformsPresent[platform] = true + end + end + + if numPlatforms >= 2 then + codelite.workspace.multiplePlatforms = true + end + + -- for each workspace config + _p(1, '') + for cfg in workspace.eachconfig(wks) do + + local cfgname = codelite.cfgname(cfg) + _p(2, '', cfgname) + + local tr = workspace.grouptree(wks) + tree.traverse(tr, { + onleaf = function(n) + local prj = n.project + _p(3, '', prj.name, cfgname) + end + }) + _p(2, '') + + end + _p(1, '') + + _p('') + end diff --git a/modules/codelite/tests/_tests.lua b/modules/codelite/tests/_tests.lua new file mode 100644 index 00000000..d94a0cd9 --- /dev/null +++ b/modules/codelite/tests/_tests.lua @@ -0,0 +1,7 @@ +require ("codelite") + +return { + "test_codelite_workspace.lua", + "test_codelite_project.lua", + "test_codelite_config.lua", +} diff --git a/modules/codelite/tests/test_codelite_config.lua b/modules/codelite/tests/test_codelite_config.lua new file mode 100644 index 00000000..931d9fa4 --- /dev/null +++ b/modules/codelite/tests/test_codelite_config.lua @@ -0,0 +1,235 @@ +--- +-- codelite/tests/test_codelite_config.lua +-- Automated test suite for CodeLite project generation. +-- Copyright (c) 2015 Manu Evans and the Premake project +--- + + + local suite = test.declare("codelite_cproj_config") + local codelite = premake.modules.codelite + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.action.set("codelite") + premake.indent(" ") + wks, prj = test.createWorkspace() + end + + local function prepare() + cfg = test.getconfig(prj, "Debug") + end + + + function suite.OnProjectCfg_Compiler() + prepare() + codelite.project.compiler(cfg) + test.capture [[ + + + ]] + end + + function suite.OnProjectCfg_Flags() + optimize "Debug" + exceptionhandling "Off" + rtti "Off" + pic "On" + symbols "On" + flags { "NoBufferSecurityCheck", "C++11" } + buildoptions { "-opt1", "-opt2" } + prepare() + codelite.project.compiler(cfg) + test.capture [[ + + + ]] + end + + function suite.OnProjectCfg_Includes() + includedirs { "dir/", "dir2" } + prepare() + codelite.project.compiler(cfg) + test.capture [[ + + + + + ]] + end + + function suite.OnProjectCfg_Defines() + defines { "TEST", "DEF" } + prepare() + codelite.project.compiler(cfg) + test.capture [[ + + + + + ]] + end + + function suite.OnProjectCfg_Linker() + prepare() + codelite.project.linker(cfg) + test.capture [[ + + + ]] + end + + function suite.OnProjectCfg_LibPath() + libdirs { "test/", "test2" } + prepare() + codelite.project.linker(cfg) + test.capture [[ + + + + + ]] + end + + function suite.OnProjectCfg_Libs() + links { "lib", "lib2" } + prepare() + codelite.project.linker(cfg) + test.capture [[ + + + + + ]] + end + + -- TODO: test sibling lib project links + + + function suite.OnProjectCfg_ResCompiler() + prepare() + codelite.project.resourceCompiler(cfg) + test.capture [[ + + ]] + end + + function suite.OnProjectCfg_ResInclude() + files { "x.rc" } + resincludedirs { "dir/" } + prepare() + codelite.project.resourceCompiler(cfg) + test.capture [[ + + + + ]] + end + + function suite.OnProjectCfg_General() + system "Windows" + prepare() + codelite.project.general(cfg) + test.capture [[ + + ]] + end + + function suite.OnProjectCfg_Environment() + prepare() + codelite.project.environment(cfg) + test.capture( +' \n' .. +' \n' .. +' ' + ) + end + + function suite.OnProjectCfg_Debugger() + prepare() + codelite.project.debugger(cfg) + test.capture [[ + + + + + + ]] + end + + function suite.OnProjectCfg_DebuggerOpts() + debugremotehost "localhost" + debugport(2345) + debugextendedprotocol(true) + debugsearchpaths { "search/", "path" } + debugconnectcommands { "connectcmd1", "cmd2" } + debugstartupcommands { "startcmd1", "cmd2" } + prepare() + codelite.project.debugger(cfg) + test.capture [[ + + search +path + connectcmd1 +cmd2 + startcmd1 +cmd2 + + ]] + end + + function suite.OnProject_PreBuild() + prebuildcommands { "cmd0", "cmd1" } + prepare() + codelite.project.preBuild(prj) + test.capture [[ + + cmd0 + cmd1 + + ]] + end + + function suite.OnProject_PreBuild() + postbuildcommands { "cmd0", "cmd1" } + prepare() + codelite.project.postBuild(prj) + test.capture [[ + + cmd0 + cmd1 + + ]] + end + + -- TODO: test custom build + + + function suite.OnProject_AdditionalRules() + prepare() + codelite.project.additionalRules(prj) + test.capture [[ + + + + + ]] + end + + function suite.OnProject_Completion() + flags { "C++11" } + prepare() + codelite.project.completion(prj) + test.capture [[ + + + + + + + ]] + end diff --git a/modules/codelite/tests/test_codelite_project.lua b/modules/codelite/tests/test_codelite_project.lua new file mode 100644 index 00000000..631ab7e1 --- /dev/null +++ b/modules/codelite/tests/test_codelite_project.lua @@ -0,0 +1,100 @@ +--- +-- codelite/tests/test_codelite_project.lua +-- Automated test suite for CodeLite project generation. +-- Copyright (c) 2015 Manu Evans and the Premake project +--- + + + local suite = test.declare("codelite_cproj") + local codelite = premake.modules.codelite + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj + + function suite.setup() + premake.action.set("codelite") + premake.indent(" ") + wks = test.createWorkspace() + end + + local function prepare() + wks = premake.oven.bakeWorkspace(wks) + prj = test.getproject(wks, 1) + end + + + function suite.OnProject_Header() + prepare() + codelite.project.header(prj) + test.capture [[ + + + ]] + end + function suite.OnProject_Header_Windowed() + kind "WindowedApp" + prepare() + codelite.project.header(prj) + test.capture [[ + + + ]] + end + function suite.OnProject_Header_Shared() + kind "SharedLib" + prepare() + codelite.project.header(prj) + test.capture [[ + + + ]] + end + + function suite.OnProject_Plugins() + prepare() + codelite.project.plugins(prj) + test.capture [[ + + ]] + end + + function suite.OnProject_Description() + prepare() + codelite.project.description(prj) + test.capture [[ + + ]] + end + + function suite.OnProject_Dependencies() + prepare() + codelite.project.dependencies(prj) + test.capture [[ + + + ]] + end + + -- TODO: dependencies with actual dependencies... + + + -- GlobalSettings is currently constants, so we'll just test it here + function suite.OnProject_Settings() + prepare() + codelite.project.settings(prj) + test.capture [[ + + + + + + + + + + + ]] + end diff --git a/modules/codelite/tests/test_codelite_workspace.lua b/modules/codelite/tests/test_codelite_workspace.lua new file mode 100644 index 00000000..0f2c0ff7 --- /dev/null +++ b/modules/codelite/tests/test_codelite_workspace.lua @@ -0,0 +1,131 @@ +--- +-- codelite/tests/test_codelite_workspace.lua +-- Validate generation for CodeLite workspaces. +-- Author Manu Evans +-- Copyright (c) 2015 Manu Evans and the Premake project +--- + + local suite = test.declare("codelite_workspace") + local codelite = premake.modules.codelite + + +-- +-- Setup +-- + + local wks, prj + + function suite.setup() + premake.action.set("codelite") + premake.indent(" ") + wks = test.createWorkspace() + end + + local function prepare() + wks = test.getWorkspace(wks) + codelite.workspace.generate(wks) + end + + +-- +-- Check the basic structure of a workspace. +-- + + function suite.onEmptyWorkspace() + wks.projects = {} + prepare() + test.capture [[ + + + + + + + + + + ]] + end + + function suite.onDefaultWorkspace() + prepare() + test.capture [[ + + + + + + + + + + + + + ]] + end + + function suite.onMultipleProjects() + test.createproject(wks) + prepare() + test.capture [[ + + + + + + + + + + + + + + + + ]] + end + + +-- +-- Projects should include relative path from workspace. +-- + + function suite.onNestedProjectPath() + location "MyProject" + prepare() + test.capture([[ + + + + + + + + + + + + + ]]) + end + + function suite.onExternalProjectPath() + location "../MyProject" + prepare() + test.capture([[ + + + + + + + + + + + + + ]]) + end diff --git a/modules/d b/modules/d deleted file mode 160000 index e854b35c..00000000 --- a/modules/d +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e854b35cf1d0bedfe16239c27a69909996af12d0 diff --git a/modules/d/LICENSE.txt b/modules/d/LICENSE.txt new file mode 100644 index 00000000..5c218d40 --- /dev/null +++ b/modules/d/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Premake nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules/d/README.md b/modules/d/README.md new file mode 100644 index 00000000..0e388cab --- /dev/null +++ b/modules/d/README.md @@ -0,0 +1,55 @@ +Premake Extension to support the [D](http://dlang.org) language + +### Features ### + +* Support actions: gmake, vs20xx (VisualD) +* Support all compilers; DMD, LDC, GDC +* Support combined and separate compilation + +### Usage ### + +Simply add: +```lua +language "D" +``` +to your project definition and populate with .d files. + +### APIs ### + +* [flags](https://github.com/premake/premake-dlang/wiki/flags) + * CodeCoverage + * Deprecated + * Documentation + * GenerateHeader + * GenerateJSON + * GenerateMap + * NoBoundsCheck + * Profile + * Quiet + * RetainPaths + * SeparateCompilation + * SymbolsLikeC + * UnitTest + * Verbose +* [versionconstants](https://github.com/premake/premake-dlang/wiki/versionconstants) +* [versionlevel](https://github.com/premake/premake-dlang/wiki/versionlevel) +* [debugconstants](https://github.com/premake/premake-dlang/wiki/debugconstants) +* [debuglevel](https://github.com/premake/premake-dlang/wiki/debuglevel) +* [docdir](https://github.com/premake/premake-dlang/wiki/docdir) +* [docname](https://github.com/premake/premake-dlang/wiki/docname) +* [headerdir](https://github.com/premake/premake-dlang/wiki/headerdir) +* [headername](https://github.com/premake/premake-dlang/wiki/headername) + +### Example ### + +The contents of your premake5.lua file would be: + +```lua +solution "MySolution" + configurations { "release", "debug" } + + project "MyDProject" + kind "ConsoleApp" + language "D" + files { "src/main.d", "src/extra.d" } +``` diff --git a/modules/d/_manifest.lua b/modules/d/_manifest.lua new file mode 100644 index 00000000..89d54266 --- /dev/null +++ b/modules/d/_manifest.lua @@ -0,0 +1,9 @@ +return { + "_preload.lua", + "d.lua", + "actions/gmake.lua", + "actions/vstudio.lua", + "tools/dmd.lua", + "tools/gdc.lua", + "tools/ldc.lua", +} diff --git a/modules/d/_preload.lua b/modules/d/_preload.lua new file mode 100644 index 00000000..ea38663e --- /dev/null +++ b/modules/d/_preload.lua @@ -0,0 +1,126 @@ +-- +-- Name: d/_preload.lua +-- Purpose: Define the D language API's. +-- Author: Manu Evans +-- Created: 2013/10/28 +-- Copyright: (c) 2013-2015 Manu Evans and the Premake project +-- + +-- TODO: +-- MonoDevelop/Xamarin Studio has 'workspaces', which correspond to collections +-- of Premake workspaces. If premake supports multiple workspaces, we should +-- write out a workspace file... + + local p = premake + local api = p.api + +-- +-- Register the D extension +-- + + p.D = "D" + + api.addAllowed("language", p.D) + api.addAllowed("floatingpoint", "None") + api.addAllowed("flags", { + "CodeCoverage", + "Deprecated", + "Documentation", + "GenerateHeader", + "GenerateJSON", + "GenerateMap", + "NoBoundsCheck", +-- "PIC", // Note: this should be supported elsewhere... + "Profile", + "Quiet", +-- "Release", // Note: We infer this flag from config.isDebugBuild() + "RetainPaths", + "SeparateCompilation", + "SymbolsLikeC", + "UnitTest", + "Verbose", + }) + + +-- +-- Register some D specific properties +-- + + api.register { + name = "versionconstants", + scope = "config", + kind = "list:string", + tokens = true, + } + + api.register { + name = "versionlevel", + scope = "config", + kind = "integer", + } + + api.register { + name = "debugconstants", + scope = "config", + kind = "list:string", + tokens = true, + } + + api.register { + name = "debuglevel", + scope = "config", + kind = "integer", + } + + api.register { + name = "docdir", + scope = "config", + kind = "path", + tokens = true, + } + + api.register { + name = "docname", + scope = "config", + kind = "string", + tokens = true, + } + + api.register { + name = "headerdir", + scope = "config", + kind = "path", + tokens = true, + } + + api.register { + name = "headername", + scope = "config", + kind = "string", + tokens = true, + } + + +-- +-- Provide information for the help output +-- + newoption + { + trigger = "dc", + value = "VALUE", + description = "Choose a D compiler", + allowed = { + { "dmd", "Digital Mars (dmd)" }, + { "gdc", "GNU GDC (gdc)" }, + { "ldc", "LLVM LDC (ldc2)" }, + } + } + + +-- +-- Decide when to load the full module +-- + + return function (cfg) + return (cfg.language == p.D) + end diff --git a/modules/d/actions/gmake.lua b/modules/d/actions/gmake.lua new file mode 100644 index 00000000..555e49b9 --- /dev/null +++ b/modules/d/actions/gmake.lua @@ -0,0 +1,370 @@ +-- +-- d/actions/gmake.lua +-- Define the D makefile action(s). +-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project +-- + + local p = premake + local m = p.modules.d + + m.make = {} + + local dmake = m.make + + local make = p.make + local cpp = p.make.cpp + local project = p.project + local config = p.config + local fileconfig = p.fileconfig + +-- This check may be unnecessary as we only 'require' this file from d.lua +-- IFF the action already exists, however this may help if this file is +-- directly required, rather than d.lua itself. + local gmake = p.action.get( 'gmake' ) + if gmake == nil then + error( "Failed to locate prequisite action 'gmake'" ) + end + +-- +-- Patch the gmake action with the allowed tools... +-- + gmake.valid_languages = table.join(gmake.valid_languages, { p.D } ) + gmake.valid_tools.dc = { "dmd", "gdc", "ldc" } + + + function m.make.separateCompilation(prj) + local some = false + local all = true + for cfg in project.eachconfig(prj) do + if cfg.flags.SeparateCompilation then + some = true + else + all = false + end + end + return iif(all, "all", iif(some, "some", "none")) + end + + +-- +-- Override the GMake action 'onProject' funtion to provide +-- D knowledge... +-- + p.override( gmake, "onProject", function(oldfn, prj) + p.escaper(make.esc) + if project.isd(prj) then + local makefile = make.getmakefilename(prj, true) + p.generate(prj, makefile, m.make.generate) + return + end + oldfn(prj) + end) + + p.override( make, "objdir", function(oldfn, cfg) + if cfg.project.language ~= "D" or cfg.flags.SeparateCompilation then + oldfn(cfg) + end + end) + + p.override( make, "objDirRules", function(oldfn, prj) + if prj.language ~= "D" or m.make.separateCompilation(prj) ~= "none" then + oldfn(prj) + end + end) + + +--- +-- Add namespace for element definition lists for p.callarray() +--- + + m.elements = {} + +-- +-- Generate a GNU make C++ project makefile, with support for the new platforms API. +-- + + m.elements.makefile = function(prj) + return { + make.header, + make.phonyRules, + m.make.configs, + m.make.objects, -- TODO: This is basically identical to make.cppObjects(), and should ideally be merged/shared + make.shellType, + m.make.targetRules, + make.targetDirRules, + make.objDirRules, + make.cppCleanRules, -- D clean code is identical to C/C++ + make.preBuildRules, + make.preLinkRules, + m.make.dFileRules, + } + end + + function m.make.generate(prj) + p.callArray(m.elements.makefile, prj) + end + + + function m.make.buildRule(prj) + _p('$(TARGET): $(SOURCEFILES) $(LDDEPS)') + _p('\t@echo Building %s', prj.name) + _p('\t$(SILENT) $(BUILDCMD)') + _p('\t$(POSTBUILDCMDS)') + end + + function m.make.linkRule(prj) + _p('$(TARGET): $(OBJECTS) $(LDDEPS)') + _p('\t@echo Linking %s', prj.name) + _p('\t$(SILENT) $(LINKCMD)') + _p('\t$(POSTBUILDCMDS)') + end + + function m.make.targetRules(prj) + local separateCompilation = m.make.separateCompilation(prj) + if separateCompilation == "all" then + m.make.linkRule(prj) + elseif separateCompilation == "none" then + m.make.buildRule(prj) + else + for cfg in project.eachconfig(prj) do + _x('ifeq ($(config),%s)', cfg.shortname) + if cfg.flags.SeparateCompilation then + m.make.linkRule(prj) + else + m.make.buildRule(prj) + end + _p('endif') + end + end + _p('') + end + + function m.make.dFileRules(prj) + local separateCompilation = m.make.separateCompilation(prj) + if separateCompilation ~= "none" then + make.cppFileRules(prj) + end + end + +-- +-- Override the 'standard' file rule to support D source files +-- + + p.override(cpp, "standardFileRules", function(oldfn, prj, node) + -- D file + if path.isdfile(node.abspath) then + _x('$(OBJDIR)/%s.o: %s', node.objname, node.relpath) + _p('\t@echo $(notdir $<)') + _p('\t$(SILENT) $(DC) $(ALL_DFLAGS) $(OUTPUTFLAG) -c $<') + else + oldfn(prj, node) + end + end) + + +-- +-- Write out the settings for a particular configuration. +-- + + m.elements.makeconfig = function(cfg) + return { + m.make.dTools, + make.target, + m.make.target, + make.objdir, + m.make.versions, + m.make.debug, + m.make.imports, + m.make.dFlags, + make.libs, + make.ldDeps, + make.ldFlags, + m.make.linkCmd, + make.preBuildCmds, + make.preLinkCmds, + make.postBuildCmds, + m.make.allRules, + make.settings, + } + end + + function m.make.configs(prj) + for cfg in project.eachconfig(prj) do + -- identify the toolset used by this configurations (would be nicer if + -- this were computed and stored with the configuration up front) + + local toolset = p.tools[_OPTIONS.dc or cfg.toolset or "dmd"] + if not toolset then + error("Invalid toolset '" + (_OPTIONS.dc or cfg.toolset) + "'") + end + + _x('ifeq ($(config),%s)', cfg.shortname) + p.callArray(m.elements.makeconfig, cfg, toolset) + _p('endif') + _p('') + end + end + + function m.make.dTools(cfg, toolset) + local tool = toolset.gettoolname(cfg, "dc") + if tool then + _p(' DC = %s', tool) + end + end + + function m.make.target(cfg, toolset) + if cfg.flags.SeparateCompilation then + _p(' OUTPUTFLAG = %s', toolset.gettarget('"$@"')) + end + end + + function m.make.versions(cfg, toolset) + _p(' VERSIONS +=%s', make.list(toolset.getversions(cfg.versionconstants, cfg.versionlevel))) + end + + function m.make.debug(cfg, toolset) + _p(' DEBUG +=%s', make.list(toolset.getdebug(cfg.debugconstants, cfg.debuglevel))) + end + + function m.make.imports(cfg, toolset) + local includes = p.esc(toolset.getimportdirs(cfg, cfg.includedirs)) + _p(' IMPORTS +=%s', make.list(includes)) + end + + function m.make.dFlags(cfg, toolset) + _p(' ALL_DFLAGS += $(DFLAGS)%s $(VERSIONS) $(DEBUG) $(IMPORTS) $(ARCH)', make.list(table.join(toolset.getdflags(cfg), cfg.buildoptions))) + end + + function m.make.linkCmd(cfg, toolset) + if cfg.flags.SeparateCompilation then + _p(' LINKCMD = $(DC) ' .. toolset.gettarget("$(TARGET)") .. ' $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)') + +-- local cc = iif(cfg.language == "C", "CC", "CXX") +-- _p(' LINKCMD = $(%s) -o $(TARGET) $(OBJECTS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS)', cc) + else + _p(' BUILDCMD = $(DC) ' .. toolset.gettarget("$(TARGET)") .. ' $(ALL_DFLAGS) $(ALL_LDFLAGS) $(LIBS) $(SOURCEFILES)') + end + end + + function m.make.allRules(cfg, toolset) + -- TODO: The C++ version has some special cases for OSX and Windows... check whether they should be here too? + if cfg.flags.SeparateCompilation then + _p('all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET)') + else + _p('all: $(TARGETDIR) prebuild prelink $(TARGET)') + end + _p('\t@:') +-- _p('') + end + + +-- +-- List the objects file for the project, and each configuration. +-- + +-- TODO: This is basically identical to make.cppObjects(), and should ideally be merged/shared + + function m.make.objects(prj) + -- create lists for intermediate files, at the project level and + -- for each configuration + local root = { sourcefiles={}, objects={} } + local configs = {} + for cfg in project.eachconfig(prj) do + configs[cfg] = { sourcefiles={}, objects={} } + end + + -- now walk the list of files in the project + local tr = project.getsourcetree(prj) + p.tree.traverse(tr, { + onleaf = function(node, depth) + -- figure out what configurations contain this file, and + -- if it uses custom build rules + local incfg = {} + local inall = true + local custom = false + for cfg in project.eachconfig(prj) do + local filecfg = fileconfig.getconfig(node, cfg) + if filecfg and not filecfg.flags.ExcludeFromBuild then + incfg[cfg] = filecfg + custom = fileconfig.hasCustomBuildRule(filecfg) + else + inall = false + end + end + + if not custom then + -- skip files that aren't compiled + if not path.isdfile(node.abspath) then + return + end + + local sourcename = node.relpath + + -- TODO: assign a unique object file name to avoid collisions + local objectname = "$(OBJDIR)/" .. node.objname .. ".o" + + -- if this file exists in all configurations, write it to + -- the project's list of files, else add to specific cfgs + if inall then + table.insert(root.sourcefiles, sourcename) + table.insert(root.objects, objectname) + else + for cfg in project.eachconfig(prj) do + if incfg[cfg] then + table.insert(configs[cfg].sourcefiles, sourcename) + table.insert(configs[cfg].objects, objectname) + end + end + end + + else + for cfg in project.eachconfig(prj) do + local filecfg = incfg[cfg] + if filecfg then + -- if the custom build outputs an object file, add it to + -- the link step automatically to match Visual Studio + local output = project.getrelative(prj, filecfg.buildoutputs[1]) + if path.isobjectfile(output) then + table.insert(configs[cfg].objects, output) + end + end + end + end + + end + }) + + local separateCompilation = m.make.separateCompilation(prj) + + -- now I can write out the lists, project level first... + function listobjects(var, list) + _p('%s \\', var) + for _, objectname in ipairs(list) do + _x('\t%s \\', objectname) + end + _p('') + end + + if separateCompilation ~= "all" then + listobjects('SOURCEFILES :=', root.sourcefiles) + end + if separateCompilation ~= "none" then + listobjects('OBJECTS :=', root.objects, 'o') + end + + -- ...then individual configurations, as needed + for cfg in project.eachconfig(prj) do + local files = configs[cfg] + if (#files.sourcefiles > 0 and separateCompilation ~= "all") or (#files.objects > 0 and separateCompilation ~= "none") then + _x('ifeq ($(config),%s)', cfg.shortname) + if #files.sourcefiles > 0 and separateCompilation ~= "all" then + listobjects(' SOURCEFILES +=', files.sourcefiles) + end + if #files.objects > 0 and separateCompilation ~= "none" then + listobjects(' OBJECTS +=', files.objects) + end + _p('endif') + end + end + _p('') + end diff --git a/modules/d/actions/vstudio.lua b/modules/d/actions/vstudio.lua new file mode 100644 index 00000000..31bef121 --- /dev/null +++ b/modules/d/actions/vstudio.lua @@ -0,0 +1,353 @@ +-- +-- d/actions/vstudio.lua +-- Generate a VisualD .visualdproj project. +-- Copyright (c) 2012-2015 Manu Evans and the Premake project +-- + + local p = premake + local m = p.modules.d + + m.visuald = {} + + local vstudio = p.vstudio + local workspace = p.workspace + local project = p.project + local config = p.config + local tree = p.tree + +-- +-- Patch the vstudio actions with D support... +-- + + for k,v in pairs({ "vs2005", "vs2008", "vs2010", "vs2012", "vs2013", "vs2015" }) do + local vs = p.action.get(v) + if vs ~= nil then + table.insert( vs.valid_languages, p.D ) + vs.valid_tools.dc = { "dmd", "gdc", "ldc" } + + p.override(vs, "onProject", function(oldfn, prj) + oldfn(prj) + if project.isd(prj) then + p.generate(prj, ".visualdproj", m.visuald.generate) + end + end) + end + end + + +-- +-- Patch a bunch of other functions +-- + + p.override(project, "isnative", function(oldfn, prj) + return project.isd(prj) or oldfn(prj) + end) + + p.override(vstudio, "projectfile", function(oldfn, prj) + if project.isd(prj) then + return p.filename(prj, ".visualdproj") + end + return oldfn(prj) + end) + + p.override(vstudio, "tool", function(oldfn, prj) + if project.isd(prj) then + return "002A2DE9-8BB6-484D-9802-7E4AD4084715" + end + return oldfn(prj) + end) + + +-- +-- Generate a Visual D project. +-- + + m.elements.project = function(prj) + return { + m.visuald.header, + m.visuald.globals, + m.visuald.projectConfigurations, + m.visuald.files, + } + + end + + function m.visuald.generate(prj) + p.eol("\r\n") + p.indent(" ") + + p.callArray(m.elements.project, prj) + + _p('') + end + + + function m.visuald.header(prj) + -- for some reason Visual D projects don't seem to have an xml header + --_p('') + _p('') + end + + function m.visuald.globals(prj) + _p(1,'{%s}', prj.uuid) + end + + +-- +-- Write out the list of project configurations, which pairs build +-- configurations with architectures. +-- + + function m.visuald.projectConfigurations(prj) + -- build a list of all architectures used in this project + + for cfg in project.eachconfig(prj) do + local prjPlatform = p.esc(vstudio.projectPlatform(cfg)) + local slnPlatform = vstudio.solutionPlatform(cfg) + local is64bit = slnPlatform == "x64" -- TODO: this seems like a hack + + _p(1,'', prjPlatform, slnPlatform) + + _p(2,'0') + _p(2,'0') + + local isWindows = false + local isDebug = string.find(cfg.buildcfg, 'Debug') ~= nil + local isOptimised = config.isOptimizedBuild(cfg) + + if cfg.kind == p.CONSOLEAPP then + _p(2,'0') + _p(2,'1') + elseif cfg.kind == p.STATICLIB then + _p(2,'1') + _p(2,'0') + elseif cfg.kind == p.SHAREDLIB then + _p(2,'2') + _p(2,'0') -- SHOULD THIS BE '2' (windows)?? + else + _p(2,'0') + _p(2,'2') + isWindows = true + end + + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(cfg.flags.Profile, '1', '0')) + _p(2,'%s', iif(cfg.flags.Quiet, '1', '0')) + _p(2,'%s', iif(cfg.flags.Verbose, '1', '0')) + _p(2,'0') + _p(2,'%s', iif(cfg.symbols == p.ON or cfg.flags.SymbolsLikeC, iif(cfg.flags.SymbolsLikeC, '2', '1'), '0')) + _p(2,'%s', iif(isOptimised, '1', '0')) + _p(2,'0') + _p(2,'%s', iif(is64bit, '1', '0')) + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(isWindows, '1', '0')) + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(cfg.flags.Deprecated, '1', '0')) + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(cfg.flags.NoBoundsCheck, '1', '0')) + _p(2,'0') + _p(2,'%s', iif(cfg.flags.UnitTest, '1', '0')) + _p(2,'%s', iif(cfg.flags.Inline or isOptimised, '1', '0')) + _p(2,'%s', iif(cfg.flags.Release or not isDebug, '1', '0')) + _p(2,'0') + + _p(2,'%s', iif(cfg.flags.FatalCompileWarnings, '1', '0')) + _p(2,'%s', iif(cfg.warnings and cfg.warnings ~= "Off", '1', '0')) + + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(cfg.pic == "On", '1', '0')) + _p(2,'%s', iif(cfg.flags.CodeCoverage, '1', '0')) + _p(2,'%s', iif(cfg.floatingpoint and cfg.floatingpoint == "None", '1', '0')) + _p(2,'2') + _p(2,'0') + + local compiler = { dmd="0", gdc="1", ldc="2" } + m.visuald.element(2, "compiler", compiler[_OPTIONS.dc or cfg.toolset or "dmd"]) + + m.visuald.element(2, "otherDMD", '0') + m.visuald.element(2, "program", '$(DMDInstallDir)windows\\bin\\dmd.exe') + + m.visuald.element(2, "imppath", cfg.includedirs) + + m.visuald.element(2, "fileImppath") + m.visuald.element(2, "outdir", path.translate(project.getrelative(cfg.project, cfg.buildtarget.directory))) + m.visuald.element(2, "objdir", path.translate(project.getrelative(cfg.project, cfg.objdir))) + m.visuald.element(2, "objname") + m.visuald.element(2, "libname") + + m.visuald.element(2, "doDocComments", iif(cfg.flags.Documentation, '1', '0')) + m.visuald.element(2, "docdir", cfg.docdir) + m.visuald.element(2, "docname", cfg.docname) + m.visuald.element(2, "modules_ddoc") + m.visuald.element(2, "ddocfiles") + + m.visuald.element(2, "doHdrGeneration", iif(cfg.flags.GenerateHeader, '1', '0')) + m.visuald.element(2, "hdrdir", cfg.headerdir) + m.visuald.element(2, "hdrname", cfg.headername) + + m.visuald.element(2, "doXGeneration", iif(cfg.flags.GenerateJSON, '1', '0')) + m.visuald.element(2, "xfilename", '$(IntDir)\\$(TargetName).json') + + m.visuald.element(2, "debuglevel", iif(cfg.debuglevel, tostring(cfg.debuglevel), '0')) + m.visuald.element(2, "debugids", cfg.debugconstants) + m.visuald.element(2, "versionlevel", iif(cfg.versionlevel, tostring(cfg.versionlevel), '0')) + m.visuald.element(2, "versionids", cfg.versionconstants) + + _p(2,'0') + _p(2,'0') + _p(2,'%s', iif(cfg.kind ~= p.SHAREDLIB or cfg.flags.NoImportLib, '0', '1')) + _p(2,'') + _p(2,'') + _p(2,'') + + _p(2,'0') + _p(2,'') + +-- _p(2,'%s', iif(cfg.symbols == p.ON, '1', '0')) + _p(2,'1') -- we will just leave this always enabled, since it's ignored if no debuginfo is written + _p(2,'$(VisualDInstallDir)cv2pdb\\cv2pdb.exe') + _p(2,'0') + _p(2,'0') + _p(2,'0') + _p(2,'') + + _p(2,'') + _p(2,'') + + local links + local explicit = vstudio.needsExplicitLink(cfg) + -- check to see if this project uses an external toolset. If so, let the + -- toolset define the format of the links + local toolset = config.toolset(cfg) + if toolset then + links = toolset.getlinks(cfg, not explicit) + else + local scope = iif(explicit, "all", "system") + links = config.getlinks(cfg, scope, "fullpath") + end + m.visuald.element(2, "libfiles", table.concat(links, " ")) + + m.visuald.element(2, "libpaths", cfg.libdirs) + _p(2,'') + _p(2,'') + + local target = config.gettargetinfo(cfg) + _p(2,'$(OutDir)\\%s', target.name) + + _p(2,'1') + + local runtime = 0 + if not cfg.flags.OmitDefaultLibrary then + if config.isDebugBuild(cfg) then + runtime = iif(cfg.flags.StaticRuntime, "2", "4") + else + runtime = iif(cfg.flags.StaticRuntime, "1", "3") + end + end + m.visuald.element(2, "cRuntime", runtime) + + local additionalOptions + if #cfg.buildoptions > 0 then + additionalOptions = table.concat(cfg.buildoptions, " ") + end + if #cfg.linkoptions > 0 then + local linkOpts = table.implode(cfg.linkoptions, "-L", "", " ") + if additionalOptions then + additionalOptions = additionalOptions .. " " .. linkOpts + else + additionalOptions = linkOpts + end + end + m.visuald.element(2, "additionalOptions", additionalOptions) + + if #cfg.prebuildcommands > 0 then + _p(2,'%s',p.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n"))) + else + _p(2,'') + end + + if #cfg.postbuildcommands > 0 then + _p(2,'%s',p.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n"))) + else + _p(2,'') + end + + _p(2,'*.obj;*.cmd;*.build;*.json;*.dep;*.o') + + _p(1,'') + end + end + + +-- +-- Write out the source file tree. +-- + + function m.visuald.files(prj) + _p(1,'', prj.name) + + local tr = project.getsourcetree(prj) + + tree.traverse(tr, { + + -- folders, virtual or otherwise, are handled at the internal nodes + onbranchenter = function(node, depth) + _p(depth, '', node.name) + end, + + onbranchexit = function(node, depth) + _p(depth, '') + end, + + -- source files are handled at the leaves + onleaf = function(node, depth) + _p(depth, '', path.translate(node.relpath)) + +-- _p(depth, '', path.translate(node.relpath)) +-- m.visuald.fileConfiguration(prj, node, depth + 1) +-- _p(depth, '') + end + + }, false, 2) + + _p(1,'') + end + + function m.visuald.fileConfiguration(prj, node, depth) + + -- maybe we'll need this in the future... + + end + + +-- +-- Output an individual project XML element. +-- + + function m.visuald.element(depth, name, value, ...) + local isTable = type(value) == "table" + if not value or (isTable and #value == 0) then + _p(depth, '<%s />', name) + else + if isTable then + value = p.esc(table.implode(value, "", "", ";")) + _p(depth, '<%s>%s', name, value, name) + else + if select('#',...) == 0 then + value = p.esc(value) + end + _x(depth, string.format('<%s>%s', name, value, name), ...) + end + end + end diff --git a/modules/d/d.lua b/modules/d/d.lua new file mode 100644 index 00000000..cc7908bb --- /dev/null +++ b/modules/d/d.lua @@ -0,0 +1,44 @@ +-- +-- d/d.lua +-- Define the D makefile action(s). +-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project +-- + + local p = premake + + p.modules.d = {} + + local m = p.modules.d + + m._VERSION = p._VERSION + m.elements = {} + + local api = p.api + + +-- +-- Patch the project table to provide knowledge of D projects +-- + function p.project.isd(prj) + return prj.language == premake.D + end + +-- +-- Patch the path table to provide knowledge of D file extenstions +-- + function path.isdfile(fname) + return path.hasextension(fname, { ".d", ".di" }) + end + + +-- +-- Patch actions +-- + include( "tools/dmd.lua" ) + include( "tools/gdc.lua" ) + include( "tools/ldc.lua" ) + + include( "actions/gmake.lua" ) + include( "actions/vstudio.lua" ) + + return m diff --git a/modules/d/tests/_tests.lua b/modules/d/tests/_tests.lua new file mode 100644 index 00000000..fed09a4e --- /dev/null +++ b/modules/d/tests/_tests.lua @@ -0,0 +1,9 @@ +require ("d") + +return { + "test_visualstudio.lua", + "test_gmake.lua", + "test_dmd.lua", + "test_gdc.lua", + "test_ldc.lua", +} diff --git a/modules/d/tests/test_dmd.lua b/modules/d/tests/test_dmd.lua new file mode 100644 index 00000000..a12f5bc6 --- /dev/null +++ b/modules/d/tests/test_dmd.lua @@ -0,0 +1,105 @@ +--- +-- d/tests/test_dmd.lua +-- Automated test suite for dmd. +-- Copyright (c) 2011-2015 Manu Evans and the Premake project +--- + + local suite = test.declare("d_dmd") + local m = premake.modules.d + + local make = premake.make + local project = premake.project + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.escaper(make.esc) + wks = test.createWorkspace() + end + + local function prepare_cfg(calls) + prj = premake.workspace.getproject(wks, 1) + local cfg = test.getconfig(prj, "Debug") + local toolset = premake.tools.dmd + premake.callArray(calls, cfg, toolset) + end + + +-- +-- Check configuration generation +-- + + function suite.dmd_dTools() + prepare_cfg({ m.make.dTools }) + test.capture [[ + DC = dmd + ]] + end + + function suite.dmd_target() + prepare_cfg({ m.make.target }) + test.capture [[ + + ]] + end + + function suite.dmd_target_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.target }) + test.capture [[ + OUTPUTFLAG = -of"$@" + ]] + end + + function suite.dmd_versions() + versionlevel (10) + versionconstants { "A", "B" } + prepare_cfg({ m.make.versions }) + test.capture [[ + VERSIONS += -version=A -version=B -version=10 + ]] + end + + function suite.dmd_debug() + debuglevel (10) + debugconstants { "A", "B" } + prepare_cfg({ m.make.debug }) + test.capture [[ + DEBUG += -debug=A -debug=B -debug=10 + ]] + end + + function suite.dmd_imports() + includedirs { "dir1", "dir2/" } + prepare_cfg({ m.make.imports }) + test.capture [[ + IMPORTS += -Idir1 -Idir2 + ]] + end + + function suite.dmd_dFlags() + prepare_cfg({ m.make.dFlags }) + test.capture [[ + ALL_DFLAGS += $(DFLAGS) -release $(VERSIONS) $(DEBUG) $(IMPORTS) $(ARCH) + ]] + end + + function suite.dmd_linkCmd() + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + BUILDCMD = $(DC) -of$(TARGET) $(ALL_DFLAGS) $(ALL_LDFLAGS) $(LIBS) $(SOURCEFILES) + ]] + end + + function suite.dmd_linkCmd_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + LINKCMD = $(DC) -of$(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS) + ]] + end diff --git a/modules/d/tests/test_gdc.lua b/modules/d/tests/test_gdc.lua new file mode 100644 index 00000000..a22ba25c --- /dev/null +++ b/modules/d/tests/test_gdc.lua @@ -0,0 +1,105 @@ +--- +-- d/tests/test_dmd.lua +-- Automated test suite for dmd. +-- Copyright (c) 2011-2015 Manu Evans and the Premake project +--- + + local suite = test.declare("d_gdc") + local m = premake.modules.d + + local make = premake.make + local project = premake.project + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.escaper(make.esc) + wks = test.createWorkspace() + end + + local function prepare_cfg(calls) + prj = premake.workspace.getproject(wks, 1) + local cfg = test.getconfig(prj, "Debug") + local toolset = premake.tools.gdc + premake.callArray(calls, cfg, toolset) + end + + +-- +-- Check configuration generation +-- + + function suite.dmd_dTools() + prepare_cfg({ m.make.dTools }) + test.capture [[ + DC = gdc + ]] + end + + function suite.dmd_target() + prepare_cfg({ m.make.target }) + test.capture [[ + + ]] + end + + function suite.dmd_target_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.target }) + test.capture [[ + OUTPUTFLAG = -o "$@" + ]] + end + + function suite.dmd_versions() + versionlevel (10) + versionconstants { "A", "B" } + prepare_cfg({ m.make.versions }) + test.capture [[ + VERSIONS += -fversion=A -fversion=B -fversion=10 + ]] + end + + function suite.dmd_debug() + debuglevel (10) + debugconstants { "A", "B" } + prepare_cfg({ m.make.debug }) + test.capture [[ + DEBUG += -fdebug=A -fdebug=B -fdebug=10 + ]] + end + + function suite.dmd_imports() + includedirs { "dir1", "dir2/" } + prepare_cfg({ m.make.imports }) + test.capture [[ + IMPORTS += -Idir1 -Idir2 + ]] + end + + function suite.dmd_dFlags() + prepare_cfg({ m.make.dFlags }) + test.capture [[ + ALL_DFLAGS += $(DFLAGS) -frelease $(VERSIONS) $(DEBUG) $(IMPORTS) $(ARCH) + ]] + end + + function suite.dmd_linkCmd() + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + BUILDCMD = $(DC) -o $(TARGET) $(ALL_DFLAGS) $(ALL_LDFLAGS) $(LIBS) $(SOURCEFILES) + ]] + end + + function suite.dmd_linkCmd_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + LINKCMD = $(DC) -o $(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS) + ]] + end diff --git a/modules/d/tests/test_gmake.lua b/modules/d/tests/test_gmake.lua new file mode 100644 index 00000000..af70043d --- /dev/null +++ b/modules/d/tests/test_gmake.lua @@ -0,0 +1,194 @@ +--- +-- d/tests/test_gmake.lua +-- Automated test suite for gmake project generation. +-- Copyright (c) 2011-2015 Manu Evans and the Premake project +--- + + local suite = test.declare("d_make") + local m = premake.modules.d + + local make = premake.make + local project = premake.project + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.escaper(make.esc) + wks = test.createWorkspace() + end + + local function prepare() + prj = premake.workspace.getproject(wks, 1) + end + + local function prepare_cfg(calls) + prj = premake.workspace.getproject(wks, 1) + local cfg = test.getconfig(prj, "Debug") + local toolset = premake.tools.dmd + premake.callArray(calls, cfg, toolset) + end + + + +-- +-- Check project generation +-- + + function suite.make_targetRules() + prepare() + m.make.targetRules(prj) + test.capture [[ +$(TARGET): $(SOURCEFILES) $(LDDEPS) + @echo Building MyProject + $(SILENT) $(BUILDCMD) + $(POSTBUILDCMDS) + + ]] + end + + function suite.make_targetRules_separateCompilation() + flags { "SeparateCompilation" } + prepare() + m.make.targetRules(prj) + test.capture [[ +$(TARGET): $(OBJECTS) $(LDDEPS) + @echo Linking MyProject + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) + + ]] + end + + function suite.make_targetRules_mixedCompilation() + configuration { "Release" } + flags { "SeparateCompilation" } + prepare() + m.make.targetRules(prj) + test.capture [[ +ifeq ($(config),debug) +$(TARGET): $(SOURCEFILES) $(LDDEPS) + @echo Building MyProject + $(SILENT) $(BUILDCMD) + $(POSTBUILDCMDS) +endif +ifeq ($(config),release) +$(TARGET): $(OBJECTS) $(LDDEPS) + @echo Linking MyProject + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) +endif + + ]] + end + + + function suite.make_fileRules() + files { "blah.d" } + prepare() + m.make.dFileRules(prj) + test.capture [[ + + ]] + end + + function suite.make_fileRules_separateCompilation() + files { "blah.d" } + flags { "SeparateCompilation" } + prepare() + m.make.dFileRules(prj) + test.capture [[ +$(OBJDIR)/blah.o: blah.d + @echo $(notdir $<) + $(SILENT) $(DC) $(ALL_DFLAGS) $(OUTPUTFLAG) -c $< + ]] + end + + function suite.make_fileRules_mixedCompilation() + files { "blah.d" } + configuration { "Release" } + flags { "SeparateCompilation" } + prepare() + m.make.dFileRules(prj) + test.capture [[ +$(OBJDIR)/blah.o: blah.d + @echo $(notdir $<) + $(SILENT) $(DC) $(ALL_DFLAGS) $(OUTPUTFLAG) -c $< + ]] + end + + + function suite.make_objects() + files { "blah.d" } + prepare() + m.make.objects(prj) + test.capture [[ +SOURCEFILES := \ + blah.d \ + + ]] + end + + function suite.make_objects_separateCompilation() + files { "blah.d" } + flags { "SeparateCompilation" } + prepare() + m.make.objects(prj) + test.capture [[ +OBJECTS := \ + $(OBJDIR)/blah.o \ + + ]] + end + + function suite.make_objects_mixedCompilation() + files { "blah.d" } + configuration { "Release" } + flags { "SeparateCompilation" } + files { "blah2.d" } + prepare() + m.make.objects(prj) + test.capture [[ +SOURCEFILES := \ + blah.d \ + +OBJECTS := \ + $(OBJDIR)/blah.o \ + +ifeq ($(config),release) + SOURCEFILES += \ + blah2.d \ + + OBJECTS += \ + $(OBJDIR)/blah2.o \ + +endif + + ]] + end + + +-- +-- Check configuration generation +-- + + function suite.make_allRules() + prepare_cfg({ m.make.allRules }) + test.capture [[ +all: $(TARGETDIR) prebuild prelink $(TARGET) + @: + ]] + end + + function suite.make_allRules_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.allRules }) + test.capture [[ +all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) + @: + ]] + end diff --git a/modules/d/tests/test_ldc.lua b/modules/d/tests/test_ldc.lua new file mode 100644 index 00000000..94cd13aa --- /dev/null +++ b/modules/d/tests/test_ldc.lua @@ -0,0 +1,105 @@ +--- +-- d/tests/test_dmd.lua +-- Automated test suite for dmd. +-- Copyright (c) 2011-2015 Manu Evans and the Premake project +--- + + local suite = test.declare("d_ldc") + local m = premake.modules.d + + local make = premake.make + local project = premake.project + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.escaper(make.esc) + wks = test.createWorkspace() + end + + local function prepare_cfg(calls) + prj = premake.workspace.getproject(wks, 1) + local cfg = test.getconfig(prj, "Debug") + local toolset = premake.tools.ldc + premake.callArray(calls, cfg, toolset) + end + + +-- +-- Check configuration generation +-- + + function suite.dmd_dTools() + prepare_cfg({ m.make.dTools }) + test.capture [[ + DC = ldc2 + ]] + end + + function suite.dmd_target() + prepare_cfg({ m.make.target }) + test.capture [[ + + ]] + end + + function suite.dmd_target_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.target }) + test.capture [[ + OUTPUTFLAG = -of="$@" + ]] + end + + function suite.dmd_versions() + versionlevel (10) + versionconstants { "A", "B" } + prepare_cfg({ m.make.versions }) + test.capture [[ + VERSIONS += -d-version=A -d-version=B -d-version=10 + ]] + end + + function suite.dmd_debug() + debuglevel (10) + debugconstants { "A", "B" } + prepare_cfg({ m.make.debug }) + test.capture [[ + DEBUG += -d-debug=A -d-debug=B -d-debug=10 + ]] + end + + function suite.dmd_imports() + includedirs { "dir1", "dir2/" } + prepare_cfg({ m.make.imports }) + test.capture [[ + IMPORTS += -I=dir1 -I=dir2 + ]] + end + + function suite.dmd_dFlags() + prepare_cfg({ m.make.dFlags }) + test.capture [[ + ALL_DFLAGS += $(DFLAGS) -release $(VERSIONS) $(DEBUG) $(IMPORTS) $(ARCH) + ]] + end + + function suite.dmd_linkCmd() + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + BUILDCMD = $(DC) -of=$(TARGET) $(ALL_DFLAGS) $(ALL_LDFLAGS) $(LIBS) $(SOURCEFILES) + ]] + end + + function suite.dmd_linkCmd_separateCompilation() + flags { "SeparateCompilation" } + prepare_cfg({ m.make.linkCmd }) + test.capture [[ + LINKCMD = $(DC) -of=$(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS) + ]] + end diff --git a/modules/d/tests/test_visualstudio.lua b/modules/d/tests/test_visualstudio.lua new file mode 100644 index 00000000..c0bc19de --- /dev/null +++ b/modules/d/tests/test_visualstudio.lua @@ -0,0 +1,74 @@ +--- +-- d/tests/test_visualstudio.lua +-- Automated test suite for VisualD project generation. +-- Copyright (c) 2011-2015 Manu Evans and the Premake project +--- + + local suite = test.declare("visual_d") + local m = premake.modules.d + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, cfg + + function suite.setup() + premake.action.set("vs2010") +-- premake.escaper(premake.vstudio.vs2005.esc) + premake.indent(" ") + wks = workspace "MyWorkspace" + configurations { "Debug", "Release" } + language "D" + kind "ConsoleApp" + end + + local function prepare() + prj = project "MyProject" + end + + local function prepare_cfg() + prj = project "MyProject" + cfg = test.getconfig(prj, "Debug") + end + + +-- +-- Check sln for the proper project entry +-- + + function suite.slnProj() + project "MyProject" + language "D" + premake.vstudio.sln2005.reorderProjects(wks) + premake.vstudio.sln2005.projects(wks) + test.capture [[ +Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "MyProject", "MyProject.visualdproj", "{42B5DBC6-AE1F-903D-F75D-41E363076E92}" +EndProject + ]] + end + + +-- +-- Project tests +-- + + function suite.OnProject_header() + prepare() + m.visuald.header(prj) + test.capture [[ + + ]] + end + + function suite.OnProject_globals() + prepare() + m.visuald.globals(prj) + test.capture [[ + {42B5DBC6-AE1F-903D-F75D-41E363076E92} + ]] + end + + + -- TODO: break up the project gen and make lots more tests... diff --git a/modules/d/tools/dmd.lua b/modules/d/tools/dmd.lua new file mode 100644 index 00000000..fc0796d8 --- /dev/null +++ b/modules/d/tools/dmd.lua @@ -0,0 +1,376 @@ +-- +-- d/tools/dmd.lua +-- Provides dmd-specific configuration strings. +-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project +-- + + local tdmd = {} + + local project = premake.project + local config = premake.config + local d = premake.modules.d + +-- +-- Set default tools +-- + tdmd.gcc = {} + tdmd.gcc.dc = "dmd" + + tdmd.optlink = {} + tdmd.optlink.dc = "dmd" + + +-- ///////////////////////////////////////////////////////////////////////// +-- dmd + GCC toolchain +-- ///////////////////////////////////////////////////////////////////////// + +-- +-- Return a list of LDFLAGS for a specific configuration. +-- + + tdmd.gcc.ldflags = { + architecture = { + x86 = { "-m32" }, + x86_64 = { "-m64" }, + }, + kind = { + SharedLib = "-shared", + StaticLib = "-lib", + } + } + + function tdmd.gcc.getldflags(cfg) + local flags = config.mapFlags(cfg, tdmd.gcc.ldflags) + return flags + end + + +-- +-- Return a list of decorated additional libraries directories. +-- + + tdmd.gcc.libraryDirectories = { + architecture = { + x86 = "-L-L/usr/lib", + x86_64 = "-L-L/usr/lib64", + } + } + + function tdmd.gcc.getLibraryDirectories(cfg) + local flags = config.mapFlags(cfg, tdmd.gcc.libraryDirectories) + + -- Scan the list of linked libraries. If any are referenced with + -- paths, add those to the list of library search paths + for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do + table.insert(flags, '-L-L' .. project.getrelative(cfg.project, dir)) + end + + return flags + end + + +-- +-- Return the list of libraries to link, decorated with flags as needed. +-- + + function tdmd.gcc.getlinks(cfg, systemonly) + local result = {} + + local links + if not systemonly then + links = config.getlinks(cfg, "siblings", "object") + for _, link in ipairs(links) do + -- skip external project references, since I have no way + -- to know the actual output target path + if not link.project.external then + if link.kind == premake.STATICLIB then + -- Don't use "-l" flag when linking static libraries; instead use + -- path/libname.a to avoid linking a shared library of the same + -- name if one is present + table.insert(result, "-L" .. project.getrelative(cfg.project, link.linktarget.abspath)) + else + table.insert(result, "-L-l" .. link.linktarget.basename) + end + end + end + end + + -- The "-l" flag is fine for system libraries + links = config.getlinks(cfg, "system", "fullpath") + for _, link in ipairs(links) do + if path.isframework(link) then + table.insert(result, "-framework " .. path.getbasename(link)) + elseif path.isobjectfile(link) then + table.insert(result, "-L" .. link) + else + table.insert(result, "-L-l" .. path.getbasename(link)) + end + end + + return result + end + + +-- ///////////////////////////////////////////////////////////////////////// +-- tdmd + OPTLINK toolchain +-- ///////////////////////////////////////////////////////////////////////// + +-- +-- Return a list of LDFLAGS for a specific configuration. +-- + + tdmd.optlink.ldflags = { + architecture = { + x86 = { "-m32" }, + x86_64 = { "-m64" }, + }, + kind = { + SharedLib = "-shared", + StaticLib = "-lib", + } + } + + function tdmd.optlink.getldflags(cfg) + local flags = config.mapFlags(cfg, tdmd.optlink.ldflags) + return flags + end + + +-- +-- Return a list of decorated additional libraries directories. +-- + + function tdmd.optlink.getLibraryDirectories(cfg) + local flags = {} + + -- Scan the list of linked libraries. If any are referenced with + -- paths, add those to the list of library search paths + for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do + table.insert(flags, '-Llib "' .. project.getrelative(cfg.project, dir) .. '"') + end + + return flags + end + + +-- +-- Returns a list of linker flags for library names. +-- + + function tdmd.optlink.getlinks(cfg) + local result = {} + + local links = config.getlinks(cfg, "dependencies", "object") + for _, link in ipairs(links) do + -- skip external project references, since I have no way + -- to know the actual output target path + if not link.project.externalname then + local linkinfo = config.getlinkinfo(link) + if link.kind == premake.STATICLIB then + table.insert(result, project.getrelative(cfg.project, linkinfo.abspath)) + end + end + end + + -- The "-l" flag is fine for system libraries + links = config.getlinks(cfg, "system", "basename") + for _, link in ipairs(links) do + if path.isobjectfile(link) then + table.insert(result, link) + elseif path.hasextension(link, premake.systems[cfg.system].staticlib.extension) then + table.insert(result, link) + end + end + + return result + + end + + +-- ///////////////////////////////////////////////////////////////////////// +-- common dmd code (either toolchain) +-- ///////////////////////////////////////////////////////////////////////// + + -- if we are compiling on windows, we need to specialise to OPTLINK as the linker +-- OR!!! if cfg.system ~= premake.WINDOWS then + if string.match( os.getversion().description, "Windows" ) ~= nil then + -- TODO: on windows, we may use OPTLINK or MSLINK (for Win64)... +-- printf("TODO: select proper linker for 32/64 bit code") + + premake.tools.dmd = tdmd.optlink + else + premake.tools.dmd = tdmd.gcc + end + + local dmd = premake.tools.dmd + + +-- +-- Returns list of D compiler flags for a configuration. +-- + + dmd.dflags = { + architecture = { + x86 = "-m32", + x86_64 = "-m64", + }, + flags = { + CodeCoverage = "-cov", + Deprecated = "-d", + Documentation = "-D", + FatalWarnings = "-w", + GenerateHeader = "-H", + GenerateJSON = "-X", + GenerateMap = "-map", + NoBoundsCheck = "-noboundscheck", + Profile = "-profile", + Quiet = "-quiet", +-- Release = "-release", + RetainPaths = "-op", + SymbolsLikeC = "-gc", + UnitTest = "-unittest", + Verbose = "-v", + }, + floatingpoint = { + None = "-nofloat", + }, + optimize = { + On = "-O -inline", + Full = "-O -inline", + Size = "-O -inline", + Speed = "-O -inline", + }, + pic = { + On = "-fPIC", + }, + warnings = { + Default = "-wi", + Extra = "-wi", + }, + symbols = { + On = "-g", + } + } + + function dmd.getdflags(cfg) + local flags = config.mapFlags(cfg, dmd.dflags) + + if config.isDebugBuild(cfg) then + table.insert(flags, "-debug") + else + table.insert(flags, "-release") + end + + -- TODO: When DMD gets CRT options, map StaticRuntime and DebugRuntime + + if cfg.flags.Documentation then + if cfg.docname then + table.insert(flags, "-Df" .. premake.quoted(cfg.docname)) + end + if cfg.docdir then + table.insert(flags, "-Dd" .. premake.quoted(cfg.docdir)) + end + end + if cfg.flags.GenerateHeader then + if cfg.headername then + table.insert(flags, "-Hf" .. premake.quoted(cfg.headername)) + end + if cfg.headerdir then + table.insert(flags, "-Hd" .. premake.quoted(cfg.headerdir)) + end + end + + return flags + end + + +-- +-- Decorate versions for the DMD command line. +-- + + function dmd.getversions(versions, level) + local result = {} + for _, version in ipairs(versions) do + table.insert(result, '-version=' .. version) + end + if level then + table.insert(result, '-version=' .. level) + end + return result + end + + +-- +-- Decorate debug constants for the DMD command line. +-- + + function dmd.getdebug(constants, level) + local result = {} + for _, constant in ipairs(constants) do + table.insert(result, '-debug=' .. constant) + end + if level then + table.insert(result, '-debug=' .. level) + end + return result + end + + +-- +-- Decorate import file search paths for the DMD command line. +-- + + function dmd.getimportdirs(cfg, dirs) + local result = {} + for _, dir in ipairs(dirs) do + dir = project.getrelative(cfg.project, dir) + table.insert(result, '-I' .. premake.quoted(dir)) + end + return result + end + + +-- +-- Returns the target name specific to compiler +-- + + function dmd.gettarget(name) + return "-of" .. name + end + + +-- +-- Returns makefile-specific configuration rules. +-- + + dmd.makesettings = { + } + + function dmd.getmakesettings(cfg) + local settings = config.mapFlags(cfg, dmd.makesettings) + return table.concat(settings) + end + + +-- +-- Retrieves the executable command name for a tool, based on the +-- provided configuration and the operating environment. +-- +-- @param cfg +-- The configuration to query. +-- @param tool +-- The tool to fetch, one of "dc" for the D compiler, or "ar" for the static linker. +-- @return +-- The executable command name for a tool, or nil if the system's +-- default value should be used. +-- + + dmd.tools = { + -- dmd will probably never support any foreign architectures...? + } + + function dmd.gettoolname(cfg, tool) + local names = dmd.tools[cfg.architecture] or dmd.tools[cfg.system] or {} + local name = names[tool] + return name or dmd[tool] + end diff --git a/modules/d/tools/gdc.lua b/modules/d/tools/gdc.lua new file mode 100644 index 00000000..d8e42558 --- /dev/null +++ b/modules/d/tools/gdc.lua @@ -0,0 +1,292 @@ +-- +-- d/tools/gdc.lua +-- Provides GDC-specific configuration strings. +-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project +-- + + premake.tools.gdc = { } + + local gdc = premake.tools.gdc + local project = premake.project + local config = premake.config + local d = premake.modules.d + + -- + -- Set default tools + -- + + gdc.dc = "gdc" + + +-- +-- Returns list of D compiler flags for a configuration. +-- + + gdc.dflags = { + architecture = { + x86 = "-m32", + x86_64 = "-m64", + }, + flags = { + Deprecated = "-fdeprecated", + Documentation = "-fdoc", + FatalWarnings = "-Werror", + GenerateHeader = "-fintfc", + GenerateJSON = "-fX", + NoBoundsCheck = "-fno-bounds-check", +-- Release = "-frelease", + RetainPaths = "-op", + SymbolsLikeC = "-fdebug-c", + UnitTest = "-funittest", + Verbose = "-fd-verbose", + }, + floatingpoint = { + Fast = "-ffast-math", + Strict = "-ffloat-store", + }, + optimize = { + Off = "-O0", + On = "-O2 -finline-functions", + Debug = "-Og", + Full = "-O3 -finline-functions", + Size = "-Os -finline-functions", + Speed = "-O3 -finline-functions", + }, + pic = { + On = "-fPIC", + }, + vectorextensions = { + AVX = "-mavx", + SSE = "-msse", + SSE2 = "-msse2", + }, + warnings = { +-- Off = "-w", +-- Default = "-w", -- TODO: check this... + Extra = "-Wall -Wextra", + }, + symbols = { + On = "-g", + } + } + + function gdc.getdflags(cfg) + local flags = config.mapFlags(cfg, gdc.dflags) + + if config.isDebugBuild(cfg) then + table.insert(flags, "-fdebug") + else + table.insert(flags, "-frelease") + end + + -- TODO: When DMD gets CRT options, map StaticRuntime and DebugRuntime + + if cfg.flags.Documentation then + if cfg.docname then + table.insert(flags, "-fdoc-file=" .. premake.quoted(cfg.docname)) + end + if cfg.docdir then + table.insert(flags, "-fdoc-dir=" .. premake.quoted(cfg.docdir)) + end + end + if cfg.flags.GenerateHeader then + if cfg.headername then + table.insert(flags, "-fintfc-file=" .. premake.quoted(cfg.headername)) + end + if cfg.headerdir then + table.insert(flags, "-fintfc-dir=" .. premake.quoted(cfg.headerdir)) + end + end + + return flags + end + + +-- +-- Decorate versions for the DMD command line. +-- + + function gdc.getversions(versions, level) + local result = {} + for _, version in ipairs(versions) do + table.insert(result, '-fversion=' .. version) + end + if level then + table.insert(result, '-fversion=' .. level) + end + return result + end + + +-- +-- Decorate debug constants for the DMD command line. +-- + + function gdc.getdebug(constants, level) + local result = {} + for _, constant in ipairs(constants) do + table.insert(result, '-fdebug=' .. constant) + end + if level then + table.insert(result, '-fdebug=' .. level) + end + return result + end + + +-- +-- Decorate import file search paths for the DMD command line. +-- + + function gdc.getimportdirs(cfg, dirs) + local result = {} + for _, dir in ipairs(dirs) do + dir = project.getrelative(cfg.project, dir) + table.insert(result, '-I' .. premake.quoted(dir)) + end + return result + end + + +-- +-- Returns the target name specific to compiler +-- + + function gdc.gettarget(name) + return "-o " .. name + end + + +-- +-- Return a list of LDFLAGS for a specific configuration. +-- + + gdc.ldflags = { + architecture = { + x86 = { "-m32" }, + x86_64 = { "-m64" }, + }, + kind = { + SharedLib = function(cfg) + local r = { iif(cfg.system == premake.MACOSX, "-dynamiclib", "-shared") } + if cfg.system == "windows" and not cfg.flags.NoImportLib then + table.insert(r, '-Wl,--out-implib="' .. cfg.linktarget.relpath .. '"') + end + return r + end, + WindowedApp = function(cfg) + if cfg.system == premake.WINDOWS then return "-mwindows" end + end, + }, + } + + function gdc.getldflags(cfg) + local flags = config.mapFlags(cfg, gdc.ldflags) + return flags + end + + +-- +-- Return a list of decorated additional libraries directories. +-- + + gdc.libraryDirectories = { + architecture = { + x86 = "-L/usr/lib", + x86_64 = "-L/usr/lib64", + } + } + + function gdc.getLibraryDirectories(cfg) + local flags = config.mapFlags(cfg, gdc.libraryDirectories) + + -- Scan the list of linked libraries. If any are referenced with + -- paths, add those to the list of library search paths + for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do + table.insert(flags, '-Wl,-L' .. project.getrelative(cfg.project, dir)) + end + + return flags + end + + +-- +-- Return the list of libraries to link, decorated with flags as needed. +-- + + function gdc.getlinks(cfg, systemonly) + local result = {} + + local links + if not systemonly then + links = config.getlinks(cfg, "siblings", "object") + for _, link in ipairs(links) do + -- skip external project references, since I have no way + -- to know the actual output target path + if not link.project.external then + if link.kind == premake.STATICLIB then + -- Don't use "-l" flag when linking static libraries; instead use + -- path/libname.a to avoid linking a shared library of the same + -- name if one is present + table.insert(result, "-Wl," .. project.getrelative(cfg.project, link.linktarget.abspath)) + else + table.insert(result, "-Wl,-l" .. link.linktarget.basename) + end + end + end + end + + -- The "-l" flag is fine for system libraries + links = config.getlinks(cfg, "system", "fullpath") + for _, link in ipairs(links) do + if path.isframework(link) then + table.insert(result, "-framework " .. path.getbasename(link)) + elseif path.isobjectfile(link) then + table.insert(result, "-Wl," .. link) + else + table.insert(result, "-Wl,-l" .. path.getbasename(link)) + end + end + + return result + end + + +-- +-- Returns makefile-specific configuration rules. +-- + + gdc.makesettings = { + } + + function gdc.getmakesettings(cfg) + local settings = config.mapFlags(cfg, gdc.makesettings) + return table.concat(settings) + end + + +-- +-- Retrieves the executable command name for a tool, based on the +-- provided configuration and the operating environment. +-- +-- @param cfg +-- The configuration to query. +-- @param tool +-- The tool to fetch, one of "dc" for the D compiler, or "ar" for the static linker. +-- @return +-- The executable command name for a tool, or nil if the system's +-- default value should be used. +-- + + gdc.tools = { + ps3 = { + dc = "ppu-lv2-gdc", + ar = "ppu-lv2-ar", + }, + } + + function gdc.gettoolname(cfg, tool) + local names = gdc.tools[cfg.architecture] or gdc.tools[cfg.system] or {} + local name = names[tool] + return name or gdc[tool] + end diff --git a/modules/d/tools/ldc.lua b/modules/d/tools/ldc.lua new file mode 100644 index 00000000..6c79840a --- /dev/null +++ b/modules/d/tools/ldc.lua @@ -0,0 +1,286 @@ +-- +-- d/tools/ldc.lua +-- Provides LDC-specific configuration strings. +-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project +-- + + premake.tools.ldc = { } + + local ldc = premake.tools.ldc + local project = premake.project + local config = premake.config + local d = premake.modules.d + + +-- +-- Set default tools +-- + + ldc.namestyle = "posix" + + +-- +-- Returns list of D compiler flags for a configuration. +-- + + + ldc.dflags = { + architecture = { + x86 = "-m32", + x86_64 = "-m64", +-- arm = "-march=arm", +-- ppc = "-march=ppc32", +-- ppc64 = "-march=ppc64", +-- spu = "-march=cellspu", +-- mips = "-march=mips", -- -march=mipsel? + }, + flags = { + Deprecated = "-d", + Documentation = "-D", + FatalWarnings = "-w", -- Use LLVM flag? : "-fatal-assembler-warnings", + GenerateHeader = "-H", + GenerateJSON = "-X", + NoBoundsCheck = "-disable-boundscheck", +-- Release = "-release", + RetainPaths = "-op", + SymbolsLikeC = "-gc", + UnitTest = "-unittest", + Verbose = "-v", + }, + floatingpoint = { + Fast = "-fp-contract=fast -enable-unsafe-fp-math", +-- Strict = "-ffloat-store", + }, + optimize = { + Off = "-O0", + On = "-O2", + Debug = "-O0", + Full = "-O3", + Size = "-Oz", + Speed = "-O3", + }, + pic = { + On = "-relocation-model=pic", + }, + vectorextensions = { + AVX = "-mattr=+avx", + SSE = "-mattr=+sse", + SSE2 = "-mattr=+sse2", + }, + warnings = { + Default = "-wi", + Extra = "-wi", -- TODO: is there a way to get extra warnings? + }, + symbols = { + On = "-g", + } + } + + function ldc.getdflags(cfg) + local flags = config.mapFlags(cfg, ldc.dflags) + + if config.isDebugBuild(cfg) then + table.insert(flags, "-d-debug") + else + table.insert(flags, "-release") + end + + -- TODO: When DMD gets CRT options, map StaticRuntime and DebugRuntime + + if cfg.flags.Documentation then + if cfg.docname then + table.insert(flags, "-Df=" .. premake.quoted(cfg.docname)) + end + if cfg.docdir then + table.insert(flags, "-Dd=" .. premake.quoted(cfg.docdir)) + end + end + if cfg.flags.GenerateHeader then + if cfg.headername then + table.insert(flags, "-Hf=" .. premake.quoted(cfg.headername)) + end + if cfg.headerdir then + table.insert(flags, "-Hd=" .. premake.quoted(cfg.headerdir)) + end + end + + return flags + end + + +-- +-- Decorate versions for the DMD command line. +-- + + function ldc.getversions(versions, level) + local result = {} + for _, version in ipairs(versions) do + table.insert(result, '-d-version=' .. version) + end + if level then + table.insert(result, '-d-version=' .. level) + end + return result + end + + +-- +-- Decorate debug constants for the DMD command line. +-- + + function ldc.getdebug(constants, level) + local result = {} + for _, constant in ipairs(constants) do + table.insert(result, '-d-debug=' .. constant) + end + if level then + table.insert(result, '-d-debug=' .. level) + end + return result + end + + +-- +-- Decorate import file search paths for the DMD command line. +-- + + function ldc.getimportdirs(cfg, dirs) + local result = {} + for _, dir in ipairs(dirs) do + dir = project.getrelative(cfg.project, dir) + table.insert(result, '-I=' .. premake.quoted(dir)) + end + return result + end + + +-- +-- Returns the target name specific to compiler +-- + + function ldc.gettarget(name) + return "-of=" .. name + end + + +-- +-- Return a list of LDFLAGS for a specific configuration. +-- + + ldc.ldflags = { + architecture = { + x86 = { "-m32" }, + x86_64 = { "-m64" }, + }, + kind = { + SharedLib = "-shared", + StaticLib = "-lib", + }, + } + + function ldc.getldflags(cfg) + local flags = config.mapFlags(cfg, ldc.ldflags) + return flags + end + + +-- +-- Return a list of decorated additional libraries directories. +-- + + ldc.libraryDirectories = { + architecture = { + x86 = "-L=-L/usr/lib", + x86_64 = "-L=-L/usr/lib64", + } + } + + function ldc.getLibraryDirectories(cfg) + local flags = config.mapFlags(cfg, ldc.libraryDirectories) + + -- Scan the list of linked libraries. If any are referenced with + -- paths, add those to the list of library search paths + for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do + table.insert(flags, '-L=-L' .. project.getrelative(cfg.project, dir)) + end + + return flags + end + + +-- +-- Return the list of libraries to link, decorated with flags as needed. +-- + + function ldc.getlinks(cfg, systemonly) + local result = {} + + local links + if not systemonly then + links = config.getlinks(cfg, "siblings", "object") + for _, link in ipairs(links) do + -- skip external project references, since I have no way + -- to know the actual output target path + if not link.project.external then + if link.kind == premake.STATICLIB then + -- Don't use "-l" flag when linking static libraries; instead use + -- path/libname.a to avoid linking a shared library of the same + -- name if one is present + table.insert(result, "-L=" .. project.getrelative(cfg.project, link.linktarget.abspath)) + else + table.insert(result, "-L=-l" .. link.linktarget.basename) + end + end + end + end + + -- The "-l" flag is fine for system libraries + links = config.getlinks(cfg, "system", "fullpath") + for _, link in ipairs(links) do + if path.isframework(link) then + table.insert(result, "-framework " .. path.getbasename(link)) + elseif path.isobjectfile(link) then + table.insert(result, "-L=" .. link) + else + table.insert(result, "-L=-l" .. path.getbasename(link)) + end + end + + return result + end + + +-- +-- Returns makefile-specific configuration rules. +-- + + ldc.makesettings = { + } + + function ldc.getmakesettings(cfg) + local settings = config.mapFlags(cfg, ldc.makesettings) + return table.concat(settings) + end + + +-- +-- Retrieves the executable command name for a tool, based on the +-- provided configuration and the operating environment. +-- +-- @param cfg +-- The configuration to query. +-- @param tool +-- The tool to fetch, one of "dc" for the D compiler, or "ar" for the static linker. +-- @return +-- The executable command name for a tool, or nil if the system's +-- default value should be used. +-- + + ldc.tools = { + dc = "ldc2", + ar = "ar", + } + + function ldc.gettoolname(cfg, tool) + return ldc.tools[tool] + end diff --git a/modules/monodevelop b/modules/monodevelop deleted file mode 160000 index 4a9f26f9..00000000 --- a/modules/monodevelop +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4a9f26f9a46795cb46492f32f1814ff74c23a339 diff --git a/modules/raw b/modules/raw deleted file mode 160000 index 4970a7b6..00000000 --- a/modules/raw +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4970a7b6bdaab013b2da0de590031e2650e78950 diff --git a/modules/raw/README.md b/modules/raw/README.md new file mode 100644 index 00000000..f4a75cff --- /dev/null +++ b/modules/raw/README.md @@ -0,0 +1,9 @@ +Premake extension to support writing the raw lua tables. + +### Usage ### + +Simply generate your project using the `raw` action: +```bash +premake5 raw +``` +and open the generated workspace.raw file in any text editor. diff --git a/modules/raw/_manifest.lua b/modules/raw/_manifest.lua new file mode 100644 index 00000000..2228f342 --- /dev/null +++ b/modules/raw/_manifest.lua @@ -0,0 +1,5 @@ +return { + "_preload.lua", + "raw.lua", + "raw_action.lua", +} diff --git a/modules/raw/_preload.lua b/modules/raw/_preload.lua new file mode 100644 index 00000000..b8bef93d --- /dev/null +++ b/modules/raw/_preload.lua @@ -0,0 +1,20 @@ +newaction +{ + trigger = "raw", + shortname = "Raw output", + description = "Generate raw representation of Premake structures", + + valid_kinds = { "ConsoleApp", "WindowedApp", "SharedLib", "StaticLib", "Makefile", "None", "Utility" }, + valid_languages = { "C", "C++" }, + valid_tools = { cc = { "clang" } }, + + onsolution = function(sln) + require('raw') + + premake.generate(sln, ".raw", premake.raw.solution) + end, +} + +return function(cfg) + return (_ACTION == "raw") +end diff --git a/modules/raw/raw.lua b/modules/raw/raw.lua new file mode 100644 index 00000000..2dd87170 --- /dev/null +++ b/modules/raw/raw.lua @@ -0,0 +1,11 @@ +local p = premake + +p.modules.raw = {} + +local m = p.modules.raw +m.elements = {} + +dofile("_preload.lua") +dofile("raw_action.lua") + +return m diff --git a/modules/raw/raw_action.lua b/modules/raw/raw_action.lua new file mode 100644 index 00000000..2d06fdf0 --- /dev/null +++ b/modules/raw/raw_action.lua @@ -0,0 +1,75 @@ +premake.raw = { } +local raw = premake.raw +local gvisited = { } + +function raw.solution(sln) + if not gvisited[sln.global] then + gvisited[sln.global] = true + raw.printTable({ global = sln.global }) + end +end + +function raw.printTable(t, i) + i = i or 0 + placement = raw._createPlacement(t) + raw._printTableRecursive(t, i, placement) +end + +function raw._printTableRecursive(t, i, placement) + elements = { } + for k, v in pairs(t) do + table.insert(elements, { key = k, value = v }) + end + + table.sort(elements, function(a, b) + local n1 = type(a.key) == "number" + local n2 = type(b.key) == "number" + if n1 ~= n2 then + return n1 + end + + local k1 = n1 and a.key or raw._encode(a.key) + local k2 = n2 and b.key or raw._encode(b.key) + return k1 < k2 + end) + + for _, elem in ipairs(elements) do + p = placement[elem.value] + if p and elem.key == p.key and t == p.parent then + _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value) .. ' {') + raw._printTableRecursive(elem.value, i + 1, placement) + _p(i, '} # ' .. raw._encode(elem.key)) + else + _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value)) + end + end +end + +function raw._createPlacement(tbl) + placement = { } + placementList = { tbl } + while #placementList ~= 0 do + parentList = { } + for _, parent in ipairs(placementList) do + for k, v in pairs(parent) do + if type(v) == "table" and not placement[v] then + table.insert(parentList, v) + placement[v] = { + parent = parent, + key = k + } + end + end + end + placementList = parentList + end + return placement +end + +function raw._encode(v) + if type(v) == "string" then + return '"' .. v .. '"' + else + return tostring(v) + end +end diff --git a/modules/xcode b/modules/xcode deleted file mode 160000 index 9427f337..00000000 --- a/modules/xcode +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9427f3373074795b16d25d2efcc836c2a2501902 diff --git a/modules/xcode/LICENSE.TXT b/modules/xcode/LICENSE.TXT new file mode 100644 index 00000000..11cc14f0 --- /dev/null +++ b/modules/xcode/LICENSE.TXT @@ -0,0 +1,27 @@ +Copyright (c) 2003-2015 Jason Perkins, Mihai Sebea and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of Premake nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/modules/xcode/_manifest.lua b/modules/xcode/_manifest.lua new file mode 100644 index 00000000..4c11a556 --- /dev/null +++ b/modules/xcode/_manifest.lua @@ -0,0 +1,7 @@ +return { + "_preload.lua", + "xcode.lua", + "xcode4_workspace.lua", + "xcode_common.lua", + "xcode_project.lua", +} diff --git a/modules/xcode/_preload.lua b/modules/xcode/_preload.lua new file mode 100644 index 00000000..4c1cc1b2 --- /dev/null +++ b/modules/xcode/_preload.lua @@ -0,0 +1,66 @@ +--- +-- xcode/_preload.lua +-- Define the Apple XCode actions and new APIs. +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +--- + + local p = premake + + +-- +-- Register new Xcode-specific project fields. +-- + + p.api.register { + name = "xcodebuildsettings", + scope = "config", + kind = "key-array", + } + + p.api.register { + name = "xcodebuildresources", + scope = "config", + kind = "list", + } + + +-- +-- Register the Xcode exporters. +-- + + newaction { + trigger = "xcode4", + shortname = "Apple Xcode 4", + description = "Generate Apple Xcode 4 project files", + + -- Xcode always uses Mac OS X path and naming conventions + + os = "macosx", + + -- The capabilities of this action + + valid_kinds = { "ConsoleApp", "WindowedApp", "SharedLib", "StaticLib", "Makefile", "None" }, + valid_languages = { "C", "C++" }, + valid_tools = { + cc = { "gcc", "clang" }, + }, + + -- Workspace and project generation logic + + onWorkspace = function(wks) + p.generate(wks, ".xcworkspace/contents.xcworkspacedata", p.modules.xcode.generateWorkspace) + end, + + onProject = function(prj) + p.generate(prj, ".xcodeproj/project.pbxproj", p.modules.xcode.generateProject) + end, + } + + +-- +-- Decide when the full module should be loaded. +-- + + return function(cfg) + return (_ACTION == "xcode4") + end diff --git a/modules/xcode/tests/_tests.lua b/modules/xcode/tests/_tests.lua new file mode 100644 index 00000000..3c9b714e --- /dev/null +++ b/modules/xcode/tests/_tests.lua @@ -0,0 +1,9 @@ +require ("xcode") + +return { + "test_header_footer.lua", + "test_xcode4_project.lua", + "test_xcode4_workspace.lua", + "test_xcode_dependencies.lua", + "test_xcode_project.lua", +} diff --git a/modules/xcode/tests/test_header_footer.lua b/modules/xcode/tests/test_header_footer.lua new file mode 100644 index 00000000..dadac52d --- /dev/null +++ b/modules/xcode/tests/test_header_footer.lua @@ -0,0 +1,48 @@ +--- +-- xcode/tests/test_header.lua +-- Validate generation for Xcode workspaces. +-- Author Jason Perkins +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +--- + + local suite = test.declare("xcode_header") + local xcode = premake.modules.xcode + + +-- +-- Setup +-- + + local wks + + function suite.setup() + wks = test.createWorkspace() + end + + local function prepare() + prj = test.getproject(wks, 1) + xcode.header(prj) + xcode.footer(prj) + end + + +-- +-- Check basic structure +-- + + function suite.onDefaults() + prepare() + test.capture [[ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} + ]] + end diff --git a/modules/xcode/tests/test_xcode4_project.lua b/modules/xcode/tests/test_xcode4_project.lua new file mode 100644 index 00000000..9729cb37 --- /dev/null +++ b/modules/xcode/tests/test_xcode4_project.lua @@ -0,0 +1,94 @@ +--- +-- tests/actions/xcode/test_xcode4_project.lua +-- Automated test suite for Xcode project generation. +-- Copyright (c) 2011-2015 Jason Perkins and the Premake project +--- + + + local suite = test.declare("xcode4_proj") + local xcode = premake.modules.xcode + + +-- +-- Replacement for xcode.newid(). Creates a synthetic ID based on the node name, +-- its intended usage (file ID, build ID, etc.) and its place in the tree. This +-- makes it easier to tell if the right ID is being used in the right places. +-- + + xcode.used_ids = {} + + xcode.newid = function(node, usage) + local name = node + if usage then + name = name .. ":" .. usage + end + + if xcode.used_ids[name] then + local count = xcode.used_ids[name] + 1 + xcode.used_ids[name] = count + name = name .. "(" .. count .. ")" + else + xcode.used_ids[name] = 1 + end + + return "[" .. name .. "]" + end + + + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local tr, wks + + function suite.teardown() + tr = nil + end + + function suite.setup() + _OS = "macosx" + _ACTION = "xcode4" + io.eol = "\n" + xcode.used_ids = { } -- reset the list of generated IDs + wks = test.createWorkspace() + end + + local function prepare() + wks = premake.oven.bakeWorkspace(wks) + xcode.prepareWorkspace(wks) + local prj = premake.workspace.getproject(wks, 1) + tr = xcode.buildprjtree(prj) + end + +--------------------------------------------------------------------------- +-- XCBuildConfiguration_Project tests +--------------------------------------------------------------------------- + + function suite.XCBuildConfigurationProject_OnSymbols() + symbols "On" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end diff --git a/modules/xcode/tests/test_xcode4_workspace.lua b/modules/xcode/tests/test_xcode4_workspace.lua new file mode 100644 index 00000000..d0f25abf --- /dev/null +++ b/modules/xcode/tests/test_xcode4_workspace.lua @@ -0,0 +1,109 @@ +--- +-- xcode/tests/test_xcode4_workspace.lua +-- Validate generation for Xcode workspaces. +-- Author Mihai Sebea +-- Modified by Jason Perkins +-- Copyright (c) 2014-2015 Jason Perkins and the Premake project +--- + + local suite = test.declare("xcode4_workspace") + local xcode = premake.modules.xcode + + +-- +-- Setup +-- + + local wks, prj + + function suite.setup() + _ACTION = "xcode4" + wks = test.createWorkspace() + end + + local function prepare() + wks = test.getWorkspace(wks) + xcode.generateWorkspace(wks) + end + + +-- +-- Check the basic structure of a workspace. +-- + + function suite.onEmptyWorkspace() + wks.projects = {} + prepare() + test.capture [[ + + + + ]] + end + + + function suite.onDefaultWorkspace() + prepare() + test.capture [[ + + + + + + ]] + end + + + function suite.onMultipleProjects() + test.createproject(wks) + prepare() + test.capture [[ + + + + + + + + ]] + end + + + +-- +-- Projects should include relative path from workspace. +-- + + function suite.onNestedProjectPath() + location "MyProject" + prepare() + test.capture [[ + + + + + + ]] + end + + function suite.onExternalProjectPath() + location "../MyProject" + prepare() + test.capture [[ + + + + + + ]] + end diff --git a/modules/xcode/tests/test_xcode_dependencies.lua b/modules/xcode/tests/test_xcode_dependencies.lua new file mode 100644 index 00000000..6bb952d7 --- /dev/null +++ b/modules/xcode/tests/test_xcode_dependencies.lua @@ -0,0 +1,317 @@ +-- +-- tests/actions/xcode/test_xcode_dependencies.lua +-- Automated test suite for Xcode project dependencies. +-- Copyright (c) 2009-2011 Jason Perkins and the Premake project +-- + + local suite = test.declare("xcode_deps") + local xcode = premake.modules.xcode + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local wks, prj, prj2, tr + + function suite.teardown() + wks = nil + prj = nil + prj2 = nil + tr = nil + end + + function suite.setup() + _ACTION = "xcode4" + xcode.used_ids = { } -- reset the list of generated IDs + + wks, prj = test.createWorkspace() + links { "MyProject2" } + + prj2 = test.createproject(wks) + kind "StaticLib" + configuration "Debug" + targetsuffix "-d" + end + + local function prepare() + wks = premake.oven.bakeWorkspace(wks) + xcode.prepareWorkspace(wks) + local prj3 = premake.workspace.getproject(wks, 1) + --prj2 = test.getproject(wks, 2) + tr = xcode.buildprjtree(prj3) + end + + +--------------------------------------------------------------------------- +-- PBXBuildFile tests +--------------------------------------------------------------------------- + + function suite.PBXBuildFile_ListsDependencyTargets_OnStaticLib() + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [libMyProject2-d.a:build] /* libMyProject2-d.a in Frameworks */ = {isa = PBXBuildFile; fileRef = [libMyProject2-d.a] /* libMyProject2-d.a */; }; +/* End PBXBuildFile section */ + ]] + end + + function suite.PBXBuildFile_ListsDependencyTargets_OnSharedLib() + kind "SharedLib" + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [libMyProject2-d.dylib:build] /* libMyProject2-d.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = [libMyProject2-d.dylib] /* libMyProject2-d.dylib */; }; +/* End PBXBuildFile section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXContainerItemProxy tests +--------------------------------------------------------------------------- + + function suite.PBXContainerItemProxy_ListsProjectConfigs() + prepare() + xcode.PBXContainerItemProxy(tr) + test.capture [[ +/* Begin PBXContainerItemProxy section */ + [MyProject2.xcodeproj:prodprox] /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = [MyProject2.xcodeproj] /* MyProject2.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = [libMyProject2-d.a:product]; + remoteInfo = "libMyProject2-d.a"; + }; + [MyProject2.xcodeproj:targprox] /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = [MyProject2.xcodeproj] /* MyProject2.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = [libMyProject2-d.a:target]; + remoteInfo = "libMyProject2-d.a"; + }; +/* End PBXContainerItemProxy section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXFileReference tests +--------------------------------------------------------------------------- + + function suite.PBXFileReference_ListsDependencies() + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject2.xcodeproj] /* libMyProject2-d.a */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "MyProject2.xcodeproj"; path = MyProject2.xcodeproj; sourceTree = SOURCE_ROOT; }; + [MyProject:product] /* MyProject */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = MyProject; path = MyProject; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + function suite.PBXFileReference_UsesRelativePaths() + prj.location = "MyProject" + prj2.location = "MyProject2" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject2.xcodeproj] /* libMyProject2-d.a */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "MyProject2.xcodeproj"; path = ../MyProject2.xcodeproj; sourceTree = SOURCE_ROOT; }; + [MyProject:product] /* MyProject */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = MyProject; path = MyProject; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXFrameworksBuildPhase tests +--------------------------------------------------------------------------- + + function suite.PBXFrameworksBuildPhase_ListsDependencies_OnStaticLib() + prepare() + xcode.PBXFrameworksBuildPhase(tr) + test.capture [[ +/* Begin PBXFrameworksBuildPhase section */ + [MyProject:fxs] /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + [libMyProject2-d.a:build] /* libMyProject2-d.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + ]] + end + + function suite.PBXFrameworksBuildPhase_ListsDependencies_OnSharedLib() + kind "SharedLib" + prepare() + xcode.PBXFrameworksBuildPhase(tr) + test.capture [[ +/* Begin PBXFrameworksBuildPhase section */ + [MyProject:fxs] /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + [libMyProject2-d.dylib:build] /* libMyProject2-d.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + ]] + end + +--------------------------------------------------------------------------- +-- PBXGroup tests +--------------------------------------------------------------------------- + + function suite.PBXGroup_ListsDependencies() + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject2.xcodeproj:prodgrp] /* Products */ = { + isa = PBXGroup; + children = ( + [libMyProject2-d.a] /* libMyProject2-d.a */, + ); + name = Products; + sourceTree = ""; + }; + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [Products] /* Products */, + [Projects] /* Projects */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; + [Projects] /* Projects */ = { + isa = PBXGroup; + children = ( + [MyProject2.xcodeproj] /* MyProject2.xcodeproj */, + ); + name = Projects; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXNativeTarget tests +--------------------------------------------------------------------------- + + function suite.PBXNativeTarget_ListsDependencies() + prepare() + xcode.PBXNativeTarget(tr) + test.capture [[ +/* Begin PBXNativeTarget section */ + [MyProject:target] /* MyProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */; + buildPhases = ( + [MyProject:rez] /* Resources */, + [MyProject:src] /* Sources */, + [MyProject:fxs] /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + [MyProject2.xcodeproj:targdep] /* PBXTargetDependency */, + ); + name = MyProject; + productInstallPath = "$(HOME)/bin"; + productName = MyProject; + productReference = [MyProject:product] /* MyProject */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXProject tests +--------------------------------------------------------------------------- + + function suite.PBXProject_ListsDependencies() + prepare() + xcode.PBXProject(tr) + test.capture [[ +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "MyProject" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = [MyProject] /* MyProject */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = [MyProject2.xcodeproj:prodgrp] /* Products */; + ProjectRef = [MyProject2.xcodeproj] /* MyProject2.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + [MyProject:target] /* MyProject */, + ); + }; +/* End PBXProject section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXReferenceProxy tests +--------------------------------------------------------------------------- + + function suite.PBXReferenceProxy_ListsDependencies() + prepare() + xcode.PBXReferenceProxy(tr) + test.capture [[ +/* Begin PBXReferenceProxy section */ + [libMyProject2-d.a] /* libMyProject2-d.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libMyProject2-d.a"; + remoteRef = [MyProject2.xcodeproj:prodprox] /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXTargetDependency tests +--------------------------------------------------------------------------- + + function suite.PBXTargetDependency_ListsDependencies() + prepare() + xcode.PBXTargetDependency(tr) + test.capture [[ +/* Begin PBXTargetDependency section */ + [MyProject2.xcodeproj:targdep] /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "libMyProject2-d.a"; + targetProxy = [MyProject2.xcodeproj:targprox] /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + ]] + end diff --git a/modules/xcode/tests/test_xcode_project.lua b/modules/xcode/tests/test_xcode_project.lua new file mode 100644 index 00000000..02570c9b --- /dev/null +++ b/modules/xcode/tests/test_xcode_project.lua @@ -0,0 +1,2032 @@ +-- +-- tests/actions/xcode/test_xcode_project.lua +-- Automated test suite for Xcode project generation. +-- Copyright (c) 2009-2011 Jason Perkins and the Premake project +-- + local suite = test.declare("xcode_project") + local xcode = premake.modules.xcode + + + +--------------------------------------------------------------------------- +-- Setup/Teardown +--------------------------------------------------------------------------- + + local tr, wks + + function suite.teardown() + tr = nil + end + + function suite.setup() + _OS = "macosx" + _ACTION = "xcode4" + premake.eol("\n") + xcode.used_ids = { } -- reset the list of generated IDs + wks = test.createWorkspace() + end + + local function prepare() + wks = premake.oven.bakeWorkspace(wks) + xcode.prepareWorkspace(wks) + local prj = test.getproject(wks, 1) + tr = xcode.buildprjtree(prj) + end + +--------------------------------------------------------------------------- +-- PBXBuildFile tests +--------------------------------------------------------------------------- + + function suite.PBXBuildFile_ListsCppSources() + files { "source.h", "source.c", "source.cpp", "Info.plist" } + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [source.c:build] /* source.c in Sources */ = {isa = PBXBuildFile; fileRef = [source.c] /* source.c */; }; + [source.cpp:build] /* source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = [source.cpp] /* source.cpp */; }; +/* End PBXBuildFile section */ + ]] + end + + function suite.PBXBuildFile_ListsObjCSources() + files { "source.h", "source.m", "source.mm", "Info.plist" } + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [source.m:build] /* source.m in Sources */ = {isa = PBXBuildFile; fileRef = [source.m] /* source.m */; }; + [source.mm:build] /* source.mm in Sources */ = {isa = PBXBuildFile; fileRef = [source.mm] /* source.mm */; }; +/* End PBXBuildFile section */ + ]] + end + + function suite.PBXBuildFile_ListsResourceFilesOnlyOnceWithGroupID() + files { "English.lproj/MainMenu.xib", "French.lproj/MainMenu.xib" } + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [MainMenu.xib:build] /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = [MainMenu.xib] /* MainMenu.xib */; }; +/* End PBXBuildFile section */ + ]] + end + + + function suite.PBXBuildFile_ListsFrameworks() + links { "Cocoa.framework", "ldap" } + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [Cocoa.framework:build] /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = [Cocoa.framework] /* Cocoa.framework */; }; +/* End PBXBuildFile section */ + ]] + end + + function suite.PBXBuildFile_IgnoresVpaths() + files { "source.h", "source.c", "source.cpp", "Info.plist" } + vpaths { ["Source Files"] = { "**.c", "**.cpp" } } + prepare() + xcode.PBXBuildFile(tr) + test.capture [[ +/* Begin PBXBuildFile section */ + [source.c:build] /* source.c in Sources */ = {isa = PBXBuildFile; fileRef = [source.c] /* source.c */; }; + [source.cpp:build] /* source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = [source.cpp] /* source.cpp */; }; +/* End PBXBuildFile section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXFileReference tests +--------------------------------------------------------------------------- + + function suite.PBXFileReference_ListsConsoleTarget() + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject:product] /* MyProject */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = MyProject; path = MyProject; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_ListsWindowedTarget() + kind "WindowedApp" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject.app:product] /* MyProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = MyProject.app; path = MyProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_ListsStaticLibTarget() + kind "StaticLib" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [libMyProject.a:product] /* libMyProject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libMyProject.a; path = libMyProject.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_ListsSharedLibTarget() + kind "SharedLib" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [libMyProject.dylib:product] /* libMyProject.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = libMyProject.dylib; path = libMyProject.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_ListsSourceFiles() + files { "source.c" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject:product] /* MyProject */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = MyProject; path = MyProject; sourceTree = BUILT_PRODUCTS_DIR; }; + [source.c] /* source.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = source.c; path = source.c; sourceTree = ""; }; + ]] + end + + + function suite.PBXFileReference_ListsXibCorrectly() + files { "English.lproj/MainMenu.xib", "French.lproj/MainMenu.xib" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [English] /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; + [French] /* French */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = French; path = French.lproj/MainMenu.xib; sourceTree = ""; }; + ]] + end + + + function suite.PBXFileReference_ListsStringsCorrectly() + files { "English.lproj/InfoPlist.strings", "French.lproj/InfoPlist.strings" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [English] /* English */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + [French] /* French */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = French; path = French.lproj/InfoPlist.strings; sourceTree = ""; }; + ]] + end + + + function suite.PBXFileReference_ListFrameworksCorrectly() + links { "Cocoa.framework/" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [Cocoa.framework] /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + ]] + end + + + function suite.PBXFileReference_leavesFrameworkLocationsAsIsWhenSupplied_pathIsSetToInput() + local inputFrameWork = 'somedir/Foo.framework' + links(inputFrameWork) + prepare() + + --io.capture() + xcode.PBXFileReference(tr) + --local str = io.captured() + --test.istrue(str:find('path = "'..inputFrameWork..'"')) + + --ms check + end + + + function suite.PBXFileReference_relativeFrameworkPathSupplied_callsError() + local inputFrameWork = '../somedir/Foo.framework' + links(inputFrameWork) + prepare() + -- ms no longer and error + -- valid case for linking relative frameworks + --local error_called = false + --local old_error = error + --error = function( ... )error_called = true end + xcode.PBXFileReference(tr) + --error = old_error + --test.istrue(error_called) + end + + function suite.PBXFileReference_ListsIconFiles() + files { "Icon.icns" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [Icon.icns] /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = Icon.icns; path = Icon.icns; sourceTree = ""; }; + ]] + end + + function suite.PBXFileReference_IgnoresTargetDir() + targetdir "bin" + kind "WindowedApp" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject.app:product] /* MyProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = MyProject.app; path = MyProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_UsesTargetSuffix() + targetsuffix "-d" + kind "SharedLib" + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [libMyProject-d.dylib:product] /* libMyProject-d.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "libMyProject-d.dylib"; path = "libMyProject-d.dylib"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + ]] + end + + + function suite.PBXFileReference_UsesFullPath_WhenParentIsVirtual() + files { "src/source.c" } + vpaths { ["Source Files"] = "**.c" } + prepare() + xcode.PBXFileReference(tr) + test.capture [[ +/* Begin PBXFileReference section */ + [MyProject:product] /* MyProject */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = MyProject; path = MyProject; sourceTree = BUILT_PRODUCTS_DIR; }; + [source.c] /* source.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = source.c; path = src/source.c; sourceTree = ""; }; + ]] + end + + +--------------------------------------------------------------------------- +-- PBXFrameworksBuildPhase tests +--------------------------------------------------------------------------- + + function suite.PBXFrameworksBuildPhase_OnNoFiles() + prepare() + xcode.PBXFrameworksBuildPhase(tr) + test.capture [[ +/* Begin PBXFrameworksBuildPhase section */ + [MyProject:fxs] /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + ]] + end + + + function suite.PBXFrameworksBuild_ListsFrameworksCorrectly() + links { "Cocoa.framework" } + prepare() + xcode.PBXFrameworksBuildPhase(tr) + test.capture [[ +/* Begin PBXFrameworksBuildPhase section */ + [MyProject:fxs] /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + [Cocoa.framework:build] /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXGroup tests +--------------------------------------------------------------------------- + + function suite.PBXGroup_OnNoFiles() + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + + function suite.PBXGroup_OnSourceFiles() + files { "source.h" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [source.h] /* source.h */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + + function suite.PBXGroup_OnSourceSubdirs() + files { "include/premake/source.h" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [source.h] /* source.h */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + + function suite.PBXGroup_pathHasPlusPlus_PathIsQuoted() + files { "RequiresQuoting++/h.h" } + prepare() + xcode.PBXGroup(tr) + + local str = premake.captured() + --test.istrue(str:find('path = "RequiresQuoting%+%+";')) + + end + + function suite.PBXGroup_SortsFiles() + files { "test.h", "source.h", "source.cpp" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [source.cpp] /* source.cpp */, + [source.h] /* source.h */, + [test.h] /* test.h */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + + function suite.PBXGroup_OnResourceFiles() + files { "English.lproj/MainMenu.xib", "French.lproj/MainMenu.xib", "Info.plist" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [Info.plist] /* Info.plist */, + [MainMenu.xib] /* MainMenu.xib */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + [Products] /* Products */ = { + isa = PBXGroup; + children = ( + [MyProject:product] /* MyProject */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + ]] + end + + + function suite.PBXGroup_OnFrameworks() + links { "Cocoa.framework" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [Frameworks] /* Frameworks */ = { + isa = PBXGroup; + children = ( + [Cocoa.framework] /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [Frameworks] /* Frameworks */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + ]] + end + + + function suite.PBXGroup_OnVpaths() + files { "include/premake/source.h" } + vpaths { ["Headers"] = "**.h" } + prepare() + xcode.PBXGroup(tr) + test.capture [[ +/* Begin PBXGroup section */ + [Headers] /* Headers */ = { + isa = PBXGroup; + children = ( + [source.h] /* source.h */, + ); + name = Headers; + sourceTree = ""; + }; + [MyProject] /* MyProject */ = { + isa = PBXGroup; + children = ( + [Headers] /* Headers */, + [Products] /* Products */, + ); + name = MyProject; + sourceTree = ""; + }; + ]] + end + + +--------------------------------------------------------------------------- +-- PBXNativeTarget tests +--------------------------------------------------------------------------- + + function suite.PBXNativeTarget_OnConsoleApp() + prepare() + xcode.PBXNativeTarget(tr) + test.capture [[ +/* Begin PBXNativeTarget section */ + [MyProject:target] /* MyProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */; + buildPhases = ( + [MyProject:rez] /* Resources */, + [MyProject:src] /* Sources */, + [MyProject:fxs] /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyProject; + productInstallPath = "$(HOME)/bin"; + productName = MyProject; + productReference = [MyProject:product] /* MyProject */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + ]] + end + + + function suite.PBXNativeTarget_OnWindowedApp() + kind "WindowedApp" + prepare() + xcode.PBXNativeTarget(tr) + test.capture [[ +/* Begin PBXNativeTarget section */ + [MyProject.app:target] /* MyProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = [MyProject.app:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */; + buildPhases = ( + [MyProject.app:rez] /* Resources */, + [MyProject.app:src] /* Sources */, + [MyProject.app:fxs] /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyProject; + productInstallPath = "$(HOME)/Applications"; + productName = MyProject; + productReference = [MyProject.app:product] /* MyProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + ]] + end + + + function suite.PBXNativeTarget_OnSharedLib() + kind "SharedLib" + prepare() + xcode.PBXNativeTarget(tr) + test.capture [[ +/* Begin PBXNativeTarget section */ + [libMyProject.dylib:target] /* MyProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = [libMyProject.dylib:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */; + buildPhases = ( + [libMyProject.dylib:rez] /* Resources */, + [libMyProject.dylib:src] /* Sources */, + [libMyProject.dylib:fxs] /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyProject; + productName = MyProject; + productReference = [libMyProject.dylib:product] /* libMyProject.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + ]] + end + + + function suite.PBXNativeTarget_OnBuildCommands() + prebuildcommands { "prebuildcmd" } + prelinkcommands { "prelinkcmd" } + postbuildcommands { "postbuildcmd" } + prepare() + xcode.PBXNativeTarget(tr) + test.capture [[ +/* Begin PBXNativeTarget section */ + [MyProject:target] /* MyProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */; + buildPhases = ( + 9607AE1010C857E500CD1376 /* Prebuild */, + [MyProject:rez] /* Resources */, + [MyProject:src] /* Sources */, + 9607AE3510C85E7E00CD1376 /* Prelink */, + [MyProject:fxs] /* Frameworks */, + 9607AE3710C85E8F00CD1376 /* Postbuild */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MyProject; + productInstallPath = "$(HOME)/bin"; + productName = MyProject; + productReference = [MyProject:product] /* MyProject */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXProject tests +--------------------------------------------------------------------------- + + function suite.PBXProject_OnProject() + prepare() + xcode.PBXProject(tr) + test.capture [[ +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "MyProject" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = [MyProject] /* MyProject */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + [MyProject:target] /* MyProject */, + ); + }; +/* End PBXProject section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXResourceBuildPhase tests +--------------------------------------------------------------------------- + + function suite.PBXResourcesBuildPhase_OnNoResources() + prepare() + xcode.PBXResourcesBuildPhase(tr) + test.capture [[ +/* Begin PBXResourcesBuildPhase section */ + [MyProject:rez] /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + ]] + end + + + function suite.PBXResourcesBuildPhase_OnResources() + files { "English.lproj/MainMenu.xib", "French.lproj/MainMenu.xib", "Info.plist" } + prepare() + xcode.PBXResourcesBuildPhase(tr) + test.capture [[ +/* Begin PBXResourcesBuildPhase section */ + [MyProject:rez] /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + [MainMenu.xib:build] /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXShellScriptBuildPhase tests +--------------------------------------------------------------------------- + + function suite.PBXShellScriptBuildPhase_OnNoScripts() + prepare() + xcode.PBXShellScriptBuildPhase(tr) + test.capture [[ + ]] + end + + + function suite.PBXShellScriptBuildPhase_OnPrebuildScripts() + prebuildcommands { 'ls src', 'cp "a" "b"' } + prepare() + xcode.PBXShellScriptBuildPhase(tr) + test.capture [[ +/* Begin PBXShellScriptBuildPhase section */ + 9607AE1010C857E500CD1376 /* Prebuild */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = Prebuild; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "ls src\ncp \"a\" \"b\""; + }; +/* End PBXShellScriptBuildPhase section */ + ]] + end + + + function suite.PBXShellScriptBuildPhase_OnPerConfigCmds() + prebuildcommands { 'ls src' } + configuration "Debug" + prebuildcommands { 'cp a b' } + prepare() + xcode.PBXShellScriptBuildPhase(tr) + test.capture [[ +/* Begin PBXShellScriptBuildPhase section */ + 9607AE1010C857E500CD1376 /* Prebuild */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = Prebuild; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "ls src\nif [ \"${CONFIGURATION}\" = \"Debug\" ]; then\ncp a b\nfi"; + }; +/* End PBXShellScriptBuildPhase section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXSourcesBuildPhase tests +--------------------------------------------------------------------------- + + function suite.PBXSourcesBuildPhase_OnNoSources() + prepare() + xcode.PBXSourcesBuildPhase(tr) + test.capture [[ +/* Begin PBXSourcesBuildPhase section */ + [MyProject:src] /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + ]] + end + + + function suite.PBXSourcesBuildPhase_OnSources() + files { "hello.cpp", "goodbye.cpp" } + prepare() + xcode.PBXSourcesBuildPhase(tr) + test.capture [[ +/* Begin PBXSourcesBuildPhase section */ + [MyProject:src] /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + [goodbye.cpp:build] /* goodbye.cpp in Sources */, + [hello.cpp:build] /* hello.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + ]] + end + + +--------------------------------------------------------------------------- +-- PBXVariantGroup tests +--------------------------------------------------------------------------- + + function suite.PBXVariantGroup_OnNoGroups() + prepare() + xcode.PBXVariantGroup(tr) + test.capture [[ +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + ]] + end + + + function suite.PBXVariantGroup_OnNoResourceGroups() + files { "English.lproj/MainMenu.xib", "French.lproj/MainMenu.xib" } + prepare() + xcode.PBXVariantGroup(tr) + test.capture [[ +/* Begin PBXVariantGroup section */ + [MainMenu.xib] /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + [English] /* English */, + [French] /* French */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + ]] + end + + +--------------------------------------------------------------------------- +-- XCBuildConfiguration_Target tests +--------------------------------------------------------------------------- + + function suite.XCBuildConfigurationTarget_OnConsoleApp() + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnWindowedApp() + kind "WindowedApp" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject.app:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = "\"$(HOME)/Applications\""; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnStaticLib() + kind "StaticLib" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [libMyProject.a:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnSharedLib() + kind "SharedLib" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [libMyProject.dylib:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_PREFIX = lib; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnTargetPrefix() + kind "SharedLib" + targetprefix "xyz" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [xyzMyProject.dylib:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_PREFIX = xyz; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnTargetExtension() + kind "SharedLib" + targetextension ".xyz" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + + --ms removed for now + --EXECUTABLE_EXTENSION = xyz; + + test.capture [[ + [libMyProject.xyz:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_PREFIX = lib; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnInfoPlist() + files { "../../MyProject-Info.plist" } + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INFOPLIST_FILE = "../../MyProject-Info.plist"; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnSymbols() + symbols "On" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnTargetSuffix() + targetsuffix "-d" + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject-d:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = "MyProject-d"; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnSinglePlatform() + platforms { "Universal32" } + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Universal32/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationTarget_OnMultiplePlatforms() + workspace("MyWorkspace") + platforms { "Universal32", "Universal64" } + prepare() + xcode.XCBuildConfiguration_Target(tr, tr.products.children[1], tr.configs[1]) + test.capture [[ + [MyProject:Debug] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = bin/Universal32/Debug; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = MyProject; + }; + name = Debug; + }; + ]] + end + + +--------------------------------------------------------------------------- +-- XCBuildConfiguration_Project tests +--------------------------------------------------------------------------- + + function suite.XCBuildConfigurationProject_OnConsoleApp() + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnOptimize() + --flags { "Optimize" } + optimize "Size" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = s; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnOptimizeSpeed() + flags { "OptimizeSpeed" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnStaticRuntime() + flags { "StaticRuntime" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnTargetDir() + targetdir "bin" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnDefines() + defines { "_DEBUG", "DEBUG" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + _DEBUG, + DEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnIncludeDirs() + includedirs { "../include", "../libs", "../name with spaces" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../include, + ../libs, + "\"../name with spaces\"", + ); + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnBuildOptions() + buildoptions { "build option 1", "build option 2" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = ( + "build option 1", + "build option 2", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnLinks() + links { "Cocoa.framework", "ldap" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "-lldap", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + function suite.XCBuildConfigurationProject_OnLinkOptions() + linkoptions { "link option 1", "link option 2" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "link option 1", + "link option 2", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnExtraWarnings() + --flags { "ExtraWarnings" } + warnings "Extra" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + WARNING_CFLAGS = "-Wall -Wextra"; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnFatalWarnings() + flags { "FatalWarnings" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnFloatFast() + flags { "FloatFast" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = ( + "-ffast-math", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnFloatStrict() + flags { "FloatStrict" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = ( + "-ffloat-store", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNoEditAndContinue() + flags { "NoEditAndContinue" } + symbols "On" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNoExceptions() + exceptionhandling "Off" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNoFramePointer() + flags { "NoFramePointer" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + OTHER_CFLAGS = ( + "-fomit-frame-pointer", + ); + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNoPCH() + pchheader "MyProject_Prefix.pch" + flags { "NoPCH" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNoRTTI() + rtti "Off" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_CPP_RTTI = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnSymbols() + symbols "On" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnLibDirs() + libdirs { "mylibs1", "mylibs2" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LIBRARY_SEARCH_PATHS = ( + mylibs1, + mylibs2, + ); + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnPCH() + pchheader "MyProject_Prefix.pch" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = MyProject_Prefix.pch; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnUniversal() + workspace("MyWorkspace") + platforms { "Universal" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Universal/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Universal/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnUniversal32() + workspace("MyWorkspace") + platforms { "Universal32" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Universal32/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Universal32/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnUniversal64() + workspace("MyWorkspace") + platforms { "Universal64" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Universal64/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Universal64/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnNative() + workspace("MyWorkspace") + platforms { "Native" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Native/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Native/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnX86() + workspace("MyWorkspace") + platforms { "x86" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = i386; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/x86/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/x86/Debug; + }; + name = Debug; + }; + ]] + end + + + function suite.XCBuildConfigurationProject_OnX86_64() + workspace("MyWorkspace") + platforms { "x86_64" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = x86_64; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/x86_64/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/x86_64/Debug; + }; + name = Debug; + }; + ]] + end + + function suite.XCBuildConfigurationProject_OnMultiplePlatforms() + workspace("MyWorkspace") + platforms { "Universal32", "Universal64" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + test.capture [[ + [MyProject:Debug(2)] /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Universal32/Debug; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = bin/Universal32/Debug; + }; + name = Debug; + }; + ]] + end + + +--------------------------------------------------------------------------- +-- XCBuildConfigurationList tests +--------------------------------------------------------------------------- + + function suite.XCBuildConfigurationList_OnNoPlatforms() + prepare() + xcode.XCBuildConfigurationList(tr) + test.capture [[ +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug(2)] /* Debug */, + [MyProject:Release(2)] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug] /* Debug */, + [MyProject:Release] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + ]] + end + + + function suite.XCBuildConfigurationList_OnSinglePlatforms() + platforms { "Universal32" } + prepare() + xcode.XCBuildConfigurationList(tr) + test.capture [[ +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug(2)] /* Debug */, + [MyProject:Release(2)] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug] /* Debug */, + [MyProject:Release] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + ]] + end + + + function suite.XCBuildConfigurationList_OnMultiplePlatforms() + workspace("MyWorkspace") + platforms { "Universal32", "Universal64" } + prepare() + xcode.XCBuildConfigurationList(tr) + test.capture [[ +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug(2)] /* Debug */, + [MyProject:Debug(4)] /* Debug */, + [MyProject:Release(2)] /* Release */, + [MyProject:Release(4)] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + [MyProject:cfg] /* Build configuration list for PBXNativeTarget "MyProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + [MyProject:Debug] /* Debug */, + [MyProject:Debug(3)] /* Debug */, + [MyProject:Release] /* Release */, + [MyProject:Release(3)] /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + ]] + end + +function suite.defaultVisibility_settingIsFound() + prepare() + xcode.XCBuildConfiguration(tr) + local str = premake.captured() + test.istrue(str:find('GCC_SYMBOLS_PRIVATE_EXTERN')) +end + + +function suite.defaultVisibilitySetting_setToNo() + prepare() + xcode.XCBuildConfiguration(tr) + local str = premake.captured() + test.istrue(str:find('GCC_SYMBOLS_PRIVATE_EXTERN = NO;')) +end + +function suite.releaseBuild_onlyDefaultArch_equalsNo() + flags { "Optimize" } + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[2]) + local str = premake.captured() + test.istrue(str:find('ONLY_ACTIVE_ARCH = NO;')) +end + +function suite.debugBuild_onlyDefaultArch_equalsYes() + symbols "On" + prepare() + xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) + + local str = premake.captured() + test.istrue(str:find('ONLY_ACTIVE_ARCH = YES;')) +end diff --git a/modules/xcode/xcode.lua b/modules/xcode/xcode.lua new file mode 100644 index 00000000..a10454b6 --- /dev/null +++ b/modules/xcode/xcode.lua @@ -0,0 +1,19 @@ +--- +-- xcode/xcode.lua +-- Common support code for the Apple Xcode exporters. +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +--- + + local p = premake + + p.modules.xcode = {} + + local m = p.modules.xcode + m._VERSION = p._VERSION + m.elements = {} + + include("xcode_common.lua") + include("xcode4_workspace.lua") + include("xcode_project.lua") + + return m diff --git a/modules/xcode/xcode4_workspace.lua b/modules/xcode/xcode4_workspace.lua new file mode 100644 index 00000000..b1e0e5c0 --- /dev/null +++ b/modules/xcode/xcode4_workspace.lua @@ -0,0 +1,84 @@ +--- +-- xcode/xcode4_workspace.lua +-- Generate an Xcode workspace. +-- Author Mihai Sebea +-- Modified by Jason Perkins +-- Copyright (c) 2014-2015 Jason Perkins and the Premake project +--- + + local p = premake + local m = p.modules.xcode + + + +--- +-- Generate an Xcode contents.xcworkspacedata file. +--- + + m.elements.workspace = function(wks) + return { + m.xmlDeclaration, + m.workspace, + m.workspaceFileRefs, + m.workspaceTail, + } + end + + function m.generateWorkspace(wks) + m.prepareWorkspace(wks) + p.callArray(m.elements.workspace, wks) + end + + + function m.workspace() + p.push('') + end + + + function m.workspaceTail() + -- Don't output final newline. Xcode doesn't. + premake.out('') + end + + +--- +-- Generate the list of project references. +--- + + m.elements.workspaceFileRef = function(prj) + return { + m.workspaceLocation, + } + end + + function m.workspaceFileRefs(wks) + for prj in p.workspace.eachproject(wks) do + p.push('") + p.pop('') + end + end + + + +--------------------------------------------------------------------------- +-- +-- Handlers for individual project elements +-- +--------------------------------------------------------------------------- + + + function m.workspaceLocation(prj) + local fname = p.filename(prj, ".xcodeproj") + fname = path.getrelative(prj.workspace.location, fname) + p.w('location = "group:%s"', fname) + end + + + function m.xmlDeclaration() + p.xmlUtf8(true) + end diff --git a/modules/xcode/xcode_common.lua b/modules/xcode/xcode_common.lua new file mode 100644 index 00000000..99858216 --- /dev/null +++ b/modules/xcode/xcode_common.lua @@ -0,0 +1,1177 @@ +-- +-- xcode_common.lua +-- Functions to generate the different sections of an Xcode project. +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +-- + + local p = premake + local xcode = p.modules.xcode + local tree = p.tree + local workspace = p.workspace + local project = p.project + local config = p.config + local fileconfig = p.fileconfig + + +-- +-- Return the Xcode build category for a given file, based on the file extension. +-- +-- @param node +-- The node to identify. +-- @returns +-- An Xcode build category, one of "Sources", "Resources", "Frameworks", or nil. +-- + + function xcode.getbuildcategory(node) + local categories = { + [".a"] = "Frameworks", + [".c"] = "Sources", + [".cc"] = "Sources", + [".cpp"] = "Sources", + [".cxx"] = "Sources", + [".dylib"] = "Frameworks", + [".framework"] = "Frameworks", + [".m"] = "Sources", + [".mm"] = "Sources", + [".strings"] = "Resources", + [".nib"] = "Resources", + [".xib"] = "Resources", + [".storyboard"] = "Resources", + [".icns"] = "Resources", + [".s"] = "Sources", + [".S"] = "Sources", + } + if node.isResource then + return "Resources" + end + return categories[path.getextension(node.name)] + end + + function xcode.isItemResource(project, node) + + local res; + + if project and project.xcodebuildresources then + if type(project.xcodebuildresources) == "table" then + res = project.xcodebuildresources + end + end + + local function checkItemInList(item, list) + if item then + if list then + if type(list) == "table" then + for _,v in pairs(list) do + if string.find(item, v) then + return true + end + end + end + end + end + return false + end + + --print (node.path, node.buildid, node.cfg, res) + if (checkItemInList(node.path, res)) then + return true + end + + return false + end +-- +-- Return the Xcode type for a given file, based on the file extension. +-- +-- @param fname +-- The file name to identify. +-- @returns +-- An Xcode file type, string. +-- + + function xcode.getfiletype(node, cfg) + + if node.configs then + local filecfg = fileconfig.getconfig(node, cfg) + if filecfg then + if filecfg.language == "ObjC" then + return "sourcecode.c.objc" + elseif filecfg.language == "ObjCpp" then + return "sourcecode.cpp.objcpp" + end + end + end + + local types = { + [".c"] = "sourcecode.c.c", + [".cc"] = "sourcecode.cpp.cpp", + [".cpp"] = "sourcecode.cpp.cpp", + [".css"] = "text.css", + [".cxx"] = "sourcecode.cpp.cpp", + [".S"] = "sourcecode.asm.asm", + [".framework"] = "wrapper.framework", + [".gif"] = "image.gif", + [".h"] = "sourcecode.c.h", + [".html"] = "text.html", + [".lua"] = "sourcecode.lua", + [".m"] = "sourcecode.c.objc", + [".mm"] = "sourcecode.cpp.objc", + [".nib"] = "wrapper.nib", + [".storyboard"] = "file.storyboard", + [".pch"] = "sourcecode.c.h", + [".plist"] = "text.plist.xml", + [".strings"] = "text.plist.strings", + [".xib"] = "file.xib", + [".icns"] = "image.icns", + [".s"] = "sourcecode.asm", + [".bmp"] = "image.bmp", + [".wav"] = "audio.wav", + [".xcassets"] = "folder.assetcatalog", + + } + return types[path.getextension(node.path)] or "text" + end + +-- +-- Print user configuration references contained in xcodeconfigreferences +-- @param offset +-- offset used by function _p +-- @param cfg +-- configuration +-- + + local function xcodePrintUserConfigReferences(offset, cfg, tr, kind) + local referenceName + if kind == "project" then + referenceName = cfg.xcodeconfigreferenceproject + elseif kind == "target" then + referenceName = cfg.xcodeconfigreferencetarget + end + tree.traverse(tr, { + onleaf = function(node) + filename = node.name + if node.id and path.getextension(filename) == ".xcconfig" then + if filename == referenceName then + _p(offset, 'baseConfigurationReference = %s /* %s */;', node.id, filename) + return + end + end + end + }, false) + end + + + + local escapeSpecialChars = { + ['\n'] = '\\n', + ['\r'] = '\\r', + ['\t'] = '\\t', + } + + local function escapeChar(c) + return escapeSpecialChars[c] or '\\'..c + end + + local function escapeArg(value) + value = value:gsub('[\'"\\\n\r\t ]', escapeChar) + return value + end + + local function escapeSetting(value) + value = value:gsub('["\\\n\r\t]', escapeChar) + return value + end + + local function stringifySetting(value) + value = value..'' + if not value:match('^[%a%d_./]+$') then + value = '"'..escapeSetting(value)..'"' + end + return value + end + + local function customStringifySetting(value) + value = value..'' + + local test = value:match('^[%a%d_./%+]+$') + if test then + value = '"'..escapeSetting(value)..'"' + end + return value + end + + local function printSetting(level, name, value) + if type(value) == 'function' then + value(level, name) + elseif type(value) ~= 'table' then + _p(level, '%s = %s;', stringifySetting(name), stringifySetting(value)) + --elseif #value == 1 then + --_p(level, '%s = %s;', stringifySetting(name), stringifySetting(value[1])) + elseif #value >= 1 then + _p(level, '%s = (', stringifySetting(name)) + for _, item in ipairs(value) do + _p(level + 1, '%s,', stringifySetting(item)) + end + _p(level, ');') + end + end + + local function printSettingsTable(level, settings) + -- Maintain alphabetic order to be consistent + local keys = table.keys(settings) + table.sort(keys) + for _, k in ipairs(keys) do + printSetting(level, k, settings[k]) + end + end + + local function overrideSettings(settings, overrides) + if type(overrides) == 'table' then + for name, value in pairs(overrides) do + -- Allow an override to remove a value by using false + settings[name] = iif(value ~= false, value, nil) + end + end + end + +-- +-- Return the Xcode product type, based target kind. +-- +-- @param node +-- The product node to identify. +-- @returns +-- An Xcode product type, string. +-- + + function xcode.getproducttype(node) + local types = { + ConsoleApp = "com.apple.product-type.tool", + WindowedApp = "com.apple.product-type.application", + StaticLib = "com.apple.product-type.library.static", + SharedLib = "com.apple.product-type.library.dynamic", + } + return types[node.cfg.kind] + end + + +-- +-- Return the Xcode target type, based on the target file extension. +-- +-- @param node +-- The product node to identify. +-- @returns +-- An Xcode target type, string. +-- + + function xcode.gettargettype(node) + local types = { + ConsoleApp = "\"compiled.mach-o.executable\"", + WindowedApp = "wrapper.application", + StaticLib = "archive.ar", + SharedLib = "\"compiled.mach-o.dylib\"", + } + return types[node.cfg.kind] + end + + +-- +-- Return a unique file name for a project. Since Xcode uses .xcodeproj's to +-- represent both workspaces and projects there is a likely change of a name +-- collision. Tack on a number to differentiate them. +-- +-- @param prj +-- The project being queried. +-- @returns +-- A uniqued file name +-- + + function xcode.getxcodeprojname(prj) + -- if there is a workspace with matching name, then use "projectname1.xcodeproj" + -- just get something working for now + local fname = premake.filename(prj, ".xcodeproj") + return fname + end + + +-- +-- Returns true if the file name represents a framework. +-- +-- @param fname +-- The name of the file to test. +-- + + function xcode.isframework(fname) + return (path.getextension(fname) == ".framework") + end + + +-- +-- Retrieves a unique 12 byte ID for an object. +-- This function accepts an array of parameters that will be used to generate the id. +-- +-- @returns +-- A 24-character string representing the 12 byte ID. +-- + + function xcode.newid(...) + local name = '' + local arg = {...} + for i, v in pairs(arg) do + name = name..v..'****' + end + + + return ("%08X%08X%08X"):format(name:hash(16777619), name:hash(2166136261), name:hash(46577619)) + end + + +-- +-- Create a product tree node and all projects in a workspace; assigning IDs +-- that are needed for inter-project dependencies. +-- +-- @param wks +-- The workspace to prepare. +-- + + function xcode.prepareWorkspace(wks) + -- create and cache a list of supported platforms + wks.xcode = { } + + for prj in premake.workspace.eachproject(wks) do + -- need a configuration to get the target information + local cfg = project.getconfig(prj, prj.configurations[1], prj.platforms[1]) + + -- build the product tree node + local bundlepath = cfg.buildtarget.bundlename ~= "" and cfg.buildtarget.bundlename or cfg.buildtarget.name; + if (prj.external) then + bundlepath = cfg.project.name + end + + local node = premake.tree.new(path.getname(bundlepath)) + + node.cfg = cfg + node.id = xcode.newid(node.name, "product") + node.targetid = xcode.newid(node.name, "target") + + -- attach it to the project + prj.xcode = {} + prj.xcode.projectnode = node + end + end + + +--------------------------------------------------------------------------- +-- Section generator functions, in the same order in which they appear +-- in the .pbxproj file +--------------------------------------------------------------------------- + + function xcode.PBXBuildFile(tr) + local settings = {}; + tree.traverse(tr, { + onnode = function(node) + if node.buildid then + settings[node.buildid] = function(level) + _p(level,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };', + node.buildid, node.name, xcode.getbuildcategory(node), node.id, node.name) + end + end + end + }) + + if not table.isempty(settings) then + _p('/* Begin PBXBuildFile section */') + printSettingsTable(2, settings); + _p('/* End PBXBuildFile section */') + _p('') + end + end + + + function xcode.PBXContainerItemProxy(tr) + local settings = {} + for _, node in ipairs(tr.projects.children) do + settings[node.productproxyid] = function() + _p(2,'%s /* PBXContainerItemProxy */ = {', node.productproxyid) + _p(3,'isa = PBXContainerItemProxy;') + _p(3,'containerPortal = %s /* %s */;', node.id, path.getrelative(node.parent.parent.project.location, node.path)) + _p(3,'proxyType = 2;') + _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.id) + _p(3,'remoteInfo = %s;', stringifySetting(node.project.xcode.projectnode.name)) + _p(2,'};') + end + settings[node.targetproxyid] = function() + _p(2,'%s /* PBXContainerItemProxy */ = {', node.targetproxyid) + _p(3,'isa = PBXContainerItemProxy;') + _p(3,'containerPortal = %s /* %s */;', node.id, path.getrelative(node.parent.parent.project.location, node.path)) + _p(3,'proxyType = 1;') + _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.targetid) + _p(3,'remoteInfo = %s;', stringifySetting(node.project.xcode.projectnode.name)) + _p(2,'};') + end + end + + if not table.isempty(settings) then + _p('/* Begin PBXContainerItemProxy section */') + printSettingsTable(2, settings); + _p('/* End PBXContainerItemProxy section */') + _p('') + end + end + + + function xcode.PBXFileReference(tr) + local cfg = project.getfirstconfig(tr.project) + local settings = {} + + tree.traverse(tr, { + onleaf = function(node) + -- I'm only listing files here, so ignore anything without a path + if not node.path then + return + end + + -- is this the product node, describing the output target? + if node.kind == "product" then + settings[node.id] = function(level) + _p(level,'%s /* %s */ = {isa = PBXFileReference; explicitFileType = %s; includeInIndex = 0; name = %s; path = %s; sourceTree = BUILT_PRODUCTS_DIR; };', + node.id, node.name, xcode.gettargettype(node), stringifySetting(node.name), stringifySetting(path.getname(node.cfg.buildtarget.bundlename ~= "" and node.cfg.buildtarget.bundlename or node.cfg.buildtarget.relpath))) + end + -- is this a project dependency? + elseif node.parent.parent == tr.projects then + settings[node.parent.id] = function(level) + -- ms Is there something wrong with path is relative ? + -- if we have a and b without slashes get relative should assume the same parent folder and return ../ + -- this works if we put it like below + local relpath = path.getrelative(path.getabsolute(tr.project.location), path.getabsolute(node.parent.project.location)) + _p(level,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = %s; path = %s; sourceTree = SOURCE_ROOT; };', + node.parent.id, node.name, customStringifySetting(node.parent.name), stringifySetting(path.join(relpath, node.parent.name))) + end + -- something else + else + settings[node.id] = function(level) + local pth, src + if xcode.isframework(node.path) then + --respect user supplied paths + -- look for special variable-starting paths for different sources + local nodePath = node.path + local _, matchEnd, variable = string.find(nodePath, "^%$%((.+)%)/") + if variable then + -- by skipping the last '/' we support the same absolute/relative + -- paths as before + nodePath = string.sub(nodePath, matchEnd + 1) + end + if string.find(nodePath,'/') then + if string.find(nodePath,'^%.')then + --error('relative paths are not currently supported for frameworks') + pth = path.getrelative(tr.project.location, node.path) + --print(tr.project.location, node.path , pth) + src = "SOURCE_ROOT" + variable = src + else + pth = nodePath + src = "" + end + end + -- if it starts with a variable, use that as the src instead + if variable then + src = variable + -- if we are using a different source tree, it has to be relative + -- to that source tree, so get rid of any leading '/' + if string.find(pth, '^/') then + pth = string.sub(pth, 2) + end + else + pth = "System/Library/Frameworks/" .. node.path + src = "SDKROOT" + end + else + -- something else; probably a source code file + src = "" + + if node.abspath then + pth = path.getrelative(tr.project.location, node.abspath) + else + pth = node.path + end + --end + end + _p(level,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = %s; name = %s; path = %s; sourceTree = %s; };', + node.id, node.name, xcode.getfiletype(node, cfg), stringifySetting(node.name), stringifySetting(pth), stringifySetting(src)) + end + end + end + }) + + if not table.isempty(settings) then + _p('/* Begin PBXFileReference section */') + printSettingsTable(2, settings) + _p('/* End PBXFileReference section */') + _p('') + end + end + + + function xcode.PBXFrameworksBuildPhase(tr) + _p('/* Begin PBXFrameworksBuildPhase section */') + _p(2,'%s /* Frameworks */ = {', tr.products.children[1].fxstageid) + _p(3,'isa = PBXFrameworksBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'files = (') + + -- write out library dependencies + tree.traverse(tr.frameworks, { + onleaf = function(node) + if node.buildid then + _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) + end + end + }) + + -- write out project dependencies + tree.traverse(tr.projects, { + onleaf = function(node) + if node.buildid then + _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) + end + end + }) + + _p(3,');') + _p(3,'runOnlyForDeploymentPostprocessing = 0;') + _p(2,'};') + _p('/* End PBXFrameworksBuildPhase section */') + _p('') + end + + + function xcode.PBXGroup(tr) + local settings = {} + + tree.traverse(tr, { + onnode = function(node) + -- Skip over anything that isn't a proper group + if (node.path and #node.children == 0) or node.kind == "vgroup" then + return + end + + settings[node.productgroupid or node.id] = function() + -- project references get special treatment + if node.parent == tr.projects then + _p(2,'%s /* Products */ = {', node.productgroupid) + else + _p(2,'%s /* %s */ = {', node.id, node.name) + end + + _p(3,'isa = PBXGroup;') + _p(3,'children = (') + for _, childnode in ipairs(node.children) do + _p(4,'%s /* %s */,', childnode.id, childnode.name) + end + _p(3,');') + + if node.parent == tr.projects then + _p(3,'name = Products;') + else + _p(3,'name = %s;', stringifySetting(node.name)) + + local vpath = project.getvpath(tr.project, node.name) + + if node.path and node.name ~= vpath then + local p = node.path + if node.parent.path then + p = path.getrelative(node.parent.path, node.path) + end + _p(3,'path = %s;', stringifySetting(p)) + end + end + + _p(3,'sourceTree = "";') + _p(2,'};') + end + end + }, true) + + if not table.isempty(settings) then + _p('/* Begin PBXGroup section */') + printSettingsTable(2, settings) + _p('/* End PBXGroup section */') + _p('') + end + end + + + function xcode.PBXNativeTarget(tr) + _p('/* Begin PBXNativeTarget section */') + for _, node in ipairs(tr.products.children) do + local name = tr.project.name + + -- This function checks whether there are build commands of a specific + -- type to be executed; they will be generated correctly, but the project + -- commands will not contain any per-configuration commands, so the logic + -- has to be extended a bit to account for that. + local function hasBuildCommands(which) + -- standard check...this is what existed before + if #tr.project[which] > 0 then + return true + end + -- what if there are no project-level commands? check configs... + for _, cfg in ipairs(tr.configs) do + if #cfg[which] > 0 then + return true + end + end + end + + _p(2,'%s /* %s */ = {', node.targetid, name) + _p(3,'isa = PBXNativeTarget;') + _p(3,'buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;', node.cfgsection, escapeSetting(name)) + _p(3,'buildPhases = (') + if hasBuildCommands('prebuildcommands') then + _p(4,'9607AE1010C857E500CD1376 /* Prebuild */,') + end + _p(4,'%s /* Resources */,', node.resstageid) + _p(4,'%s /* Sources */,', node.sourcesid) + if hasBuildCommands('prelinkcommands') then + _p(4,'9607AE3510C85E7E00CD1376 /* Prelink */,') + end + _p(4,'%s /* Frameworks */,', node.fxstageid) + if hasBuildCommands('postbuildcommands') then + _p(4,'9607AE3710C85E8F00CD1376 /* Postbuild */,') + end + _p(3,');') + _p(3,'buildRules = (') + _p(3,');') + + _p(3,'dependencies = (') + for _, node in ipairs(tr.projects.children) do + _p(4,'%s /* PBXTargetDependency */,', node.targetdependid) + end + _p(3,');') + + _p(3,'name = %s;', stringifySetting(name)) + + local p + if node.cfg.kind == "ConsoleApp" then + p = "$(HOME)/bin" + elseif node.cfg.kind == "WindowedApp" then + p = "$(HOME)/Applications" + end + if p then + _p(3,'productInstallPath = %s;', stringifySetting(p)) + end + + _p(3,'productName = %s;', stringifySetting(name)) + _p(3,'productReference = %s /* %s */;', node.id, node.name) + _p(3,'productType = %s;', stringifySetting(xcode.getproducttype(node))) + _p(2,'};') + end + _p('/* End PBXNativeTarget section */') + _p('') + end + + + function xcode.PBXProject(tr) + _p('/* Begin PBXProject section */') + _p(2,'08FB7793FE84155DC02AAC07 /* Project object */ = {') + _p(3,'isa = PBXProject;') + _p(3,'buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */;', tr.name) + _p(3,'compatibilityVersion = "Xcode 3.2";') + _p(3,'hasScannedForEncodings = 1;') + _p(3,'mainGroup = %s /* %s */;', tr.id, tr.name) + _p(3,'projectDirPath = "";') + + if #tr.projects.children > 0 then + _p(3,'projectReferences = (') + for _, node in ipairs(tr.projects.children) do + _p(4,'{') + _p(5,'ProductGroup = %s /* Products */;', node.productgroupid) + _p(5,'ProjectRef = %s /* %s */;', node.id, path.getname(node.path)) + _p(4,'},') + end + _p(3,');') + end + + _p(3,'projectRoot = "";') + _p(3,'targets = (') + for _, node in ipairs(tr.products.children) do + _p(4,'%s /* %s */,', node.targetid, node.name) + end + _p(3,');') + _p(2,'};') + _p('/* End PBXProject section */') + _p('') + end + + + function xcode.PBXReferenceProxy(tr) + local settings = {} + + tree.traverse(tr.projects, { + onleaf = function(node) + settings[node.id] = function() + _p(2,'%s /* %s */ = {', node.id, node.name) + _p(3,'isa = PBXReferenceProxy;') + _p(3,'fileType = %s;', xcode.gettargettype(node)) + _p(3,'path = %s;', stringifySetting(node.name)) + _p(3,'remoteRef = %s /* PBXContainerItemProxy */;', node.parent.productproxyid) + _p(3,'sourceTree = BUILT_PRODUCTS_DIR;') + _p(2,'};') + end + end + }) + + if not table.isempty(settings) then + _p('/* Begin PBXReferenceProxy section */') + printSettingsTable(2, settings) + _p('/* End PBXReferenceProxy section */') + _p('') + end + end + + + function xcode.PBXResourcesBuildPhase(tr) + _p('/* Begin PBXResourcesBuildPhase section */') + for _, target in ipairs(tr.products.children) do + _p(2,'%s /* Resources */ = {', target.resstageid) + _p(3,'isa = PBXResourcesBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'files = (') + tree.traverse(tr, { + onnode = function(node) + if xcode.getbuildcategory(node) == "Resources" then + _p(4,'%s /* %s in Resources */,', node.buildid, node.name) + end + end + }) + _p(3,');') + _p(3,'runOnlyForDeploymentPostprocessing = 0;') + _p(2,'};') + end + _p('/* End PBXResourcesBuildPhase section */') + _p('') + end + + function xcode.PBXShellScriptBuildPhase(tr) + local wrapperWritten = false + + local function doblock(id, name, which) + -- start with the project-level commands (most common) + local prjcmds = tr.project[which] + local commands = table.join(prjcmds, {}) + + -- see if there are any config-specific commands to add + for _, cfg in ipairs(tr.configs) do + local cfgcmds = cfg[which] + if #cfgcmds > #prjcmds then + table.insert(commands, 'if [ "${CONFIGURATION}" = "' .. cfg.buildcfg .. '" ]; then') + for i = #prjcmds + 1, #cfgcmds do + table.insert(commands, cfgcmds[i]) + end + table.insert(commands, 'fi') + end + end + + if #commands > 0 then + commands = os.translateCommands(commands, p.MACOSX) + if not wrapperWritten then + _p('/* Begin PBXShellScriptBuildPhase section */') + wrapperWritten = true + end + _p(2,'%s /* %s */ = {', id, name) + _p(3,'isa = PBXShellScriptBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'files = (') + _p(3,');') + _p(3,'inputPaths = ('); + _p(3,');'); + _p(3,'name = %s;', name); + _p(3,'outputPaths = ('); + _p(3,');'); + _p(3,'runOnlyForDeploymentPostprocessing = 0;'); + _p(3,'shellPath = /bin/sh;'); + _p(3,'shellScript = %s;', stringifySetting(table.concat(commands, '\n'))) + _p(2,'};') + end + end + + doblock("9607AE1010C857E500CD1376", "Prebuild", "prebuildcommands") + doblock("9607AE3510C85E7E00CD1376", "Prelink", "prelinkcommands") + doblock("9607AE3710C85E8F00CD1376", "Postbuild", "postbuildcommands") + + if wrapperWritten then + _p('/* End PBXShellScriptBuildPhase section */') + end + end + + + function xcode.PBXSourcesBuildPhase(tr) + _p('/* Begin PBXSourcesBuildPhase section */') + for _, target in ipairs(tr.products.children) do + _p(2,'%s /* Sources */ = {', target.sourcesid) + _p(3,'isa = PBXSourcesBuildPhase;') + _p(3,'buildActionMask = 2147483647;') + _p(3,'files = (') + tree.traverse(tr, { + onleaf = function(node) + if xcode.getbuildcategory(node) == "Sources" then + _p(4,'%s /* %s in Sources */,', node.buildid, node.name) + end + end + }) + _p(3,');') + _p(3,'runOnlyForDeploymentPostprocessing = 0;') + _p(2,'};') + end + _p('/* End PBXSourcesBuildPhase section */') + _p('') + end + + + function xcode.PBXVariantGroup(tr) + local settings = {} + tree.traverse(tr, { + onbranch = function(node) + settings[node.id] = function() + if node.kind == "vgroup" then + _p(2,'%s /* %s */ = {', node.id, node.name) + _p(3,'isa = PBXVariantGroup;') + _p(3,'children = (') + for _, lang in ipairs(node.children) do + _p(4,'%s /* %s */,', lang.id, lang.name) + end + _p(3,');') + _p(3,'name = %s;', node.name) + _p(3,'sourceTree = "";') + _p(2,'};') + end + end + end + }) + + if not table.isempty(settings) then + _p('/* Begin PBXVariantGroup section */') + printSettingsTable(2, settings) + _p('/* End PBXVariantGroup section */') + _p('') + end + end + + + function xcode.PBXTargetDependency(tr) + local settings = {} + tree.traverse(tr.projects, { + onleaf = function(node) + settings[node.parent.targetdependid] = function() + _p(2,'%s /* PBXTargetDependency */ = {', node.parent.targetdependid) + _p(3,'isa = PBXTargetDependency;') + _p(3,'name = %s;', stringifySetting(node.name)) + _p(3,'targetProxy = %s /* PBXContainerItemProxy */;', node.parent.targetproxyid) + _p(2,'};') + end + end + }) + + if not table.isempty(settings) then + _p('/* Begin PBXTargetDependency section */') + printSettingsTable(2, settings) + _p('/* End PBXTargetDependency section */') + _p('') + end + end + + + function xcode.XCBuildConfiguration_Target(tr, target, cfg) + local settings = {} + + settings['ALWAYS_SEARCH_USER_PATHS'] = 'NO' + + if not (cfg.symbols == p.ON) then + settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym' + end + + if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= '' then + settings['EXECUTABLE_PREFIX'] = cfg.buildtarget.prefix + end + + --[[if cfg.targetextension then + local ext = cfg.targetextension + ext = iif(ext:startswith('.'), ext:sub(2), ext) + settings['EXECUTABLE_EXTENSION'] = ext + end]] + + local outdir = path.getrelative(tr.project.location, path.getdirectory(cfg.buildtarget.relpath)) + if outdir ~= "." then + settings['CONFIGURATION_BUILD_DIR'] = outdir + end + + settings['GCC_DYNAMIC_NO_PIC'] = 'NO' + + if tr.infoplist then + settings['INFOPLIST_FILE'] = config.findfile(cfg, path.getextension(tr.infoplist.name)) + end + + installpaths = { + ConsoleApp = '/usr/local/bin', + WindowedApp = '"$(HOME)/Applications"', + SharedLib = '/usr/local/lib', + StaticLib = '/usr/local/lib', + } + settings['INSTALL_PATH'] = installpaths[cfg.kind] + + local fileNameList = {} + local file_tree = project.getsourcetree(tr.project) + tree.traverse(tr, { + onnode = function(node) + if node.buildid and not node.isResource and node.abspath then + -- ms this seems to work on visual studio !!! + -- why not in xcode ?? + local filecfg = fileconfig.getconfig(node, cfg) + if filecfg and filecfg.flags.ExcludeFromBuild then + --fileNameList = fileNameList .. " " ..filecfg.name + table.insert(fileNameList, escapeArg(node.name)) + end + + --ms new way + -- if the file is not in this config file list excluded it from build !!! + --if not cfg.files[node.abspath] then + -- table.insert(fileNameList, escapeArg(node.name)) + --end + end + end + }) + + if not table.isempty(fileNameList) then + settings['EXCLUDED_SOURCE_FILE_NAMES'] = fileNameList + end + settings['PRODUCT_NAME'] = cfg.buildtarget.basename + + --ms not by default ...add it manually if you need it + --settings['COMBINE_HIDPI_IMAGES'] = 'YES' + + overrideSettings(settings, cfg.xcodebuildsettings) + + _p(2,'%s /* %s */ = {', cfg.xcode.targetid, cfg.buildcfg) + _p(3,'isa = XCBuildConfiguration;') + _p(3,'buildSettings = {') + printSettingsTable(4, settings) + _p(3,'};') + printSetting(3, 'name', cfg.buildcfg); + _p(2,'};') + end + + + function xcode.XCBuildConfiguration_Project(tr, cfg) + local settings = {} + + local archs = { + Native = "$(NATIVE_ARCH_ACTUAL)", + x86 = "i386", + x86_64 = "x86_64", + Universal32 = "$(ARCHS_STANDARD_32_BIT)", + Universal64 = "$(ARCHS_STANDARD_64_BIT)", + Universal = "$(ARCHS_STANDARD_32_64_BIT)", + } + + settings['ARCHS'] = archs[cfg.platform or "Native"] + + --ms This is the default so don;t write it + --settings['SDKROOT'] = 'macosx' + + local targetdir = path.getdirectory(cfg.buildtarget.relpath) + if targetdir ~= "." then + settings['CONFIGURATION_BUILD_DIR'] = '$(SYMROOT)' + end + + settings['CONFIGURATION_TEMP_DIR'] = '$(OBJROOT)' + + if cfg.symbols == p.ON then + settings['COPY_PHASE_STRIP'] = 'NO' + end + + settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu99' + + if cfg.exceptionhandling == p.OFF then + settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'NO' + end + + if cfg.rtti == p.OFF then + settings['GCC_ENABLE_CPP_RTTI'] = 'NO' + end + + if cfg.symbols == p.ON and not cfg.flags.NoEditAndContinue then + settings['GCC_ENABLE_FIX_AND_CONTINUE'] = 'YES' + end + + if cfg.exceptionhandling == p.OFF then + settings['GCC_ENABLE_OBJC_EXCEPTIONS'] = 'NO' + end + + local optimizeMap = { On = 3, Size = 's', Speed = 3, Full = 'fast', Debug = 1 } + settings['GCC_OPTIMIZATION_LEVEL'] = optimizeMap[cfg.optimize] or 0 + + if cfg.pchheader and not cfg.flags.NoPCH then + settings['GCC_PRECOMPILE_PREFIX_HEADER'] = 'YES' + settings['GCC_PREFIX_HEADER'] = cfg.pchheader + end + + settings['GCC_PREPROCESSOR_DEFINITIONS'] = cfg.defines + + settings["GCC_SYMBOLS_PRIVATE_EXTERN"] = 'NO' + + if cfg.flags.FatalWarnings then + settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES' + end + + settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'YES' + settings['GCC_WARN_UNUSED_VARIABLE'] = 'YES' + + local includedirs = project.getrelative(cfg.project, cfg.includedirs) + for i,v in ipairs(includedirs) do + cfg.includedirs[i] = premake.quoted(v) + end + settings['HEADER_SEARCH_PATHS'] = table.join(cfg.includedirs, cfg.sysincludedirs) + + for i,v in ipairs(cfg.libdirs) do + cfg.libdirs[i] = premake.project.getrelative(cfg.project, cfg.libdirs[i]) + end + settings['LIBRARY_SEARCH_PATHS'] = cfg.libdirs + + for i,v in ipairs(cfg.frameworkdirs) do + cfg.frameworkdirs[i] = premake.project.getrelative(cfg.project, cfg.frameworkdirs[i]) + end + settings['FRAMEWORK_SEARCH_PATHS'] = cfg.frameworkdirs + + local objDir = path.getrelative(tr.project.location, cfg.objdir) + settings['OBJROOT'] = objDir + + settings['ONLY_ACTIVE_ARCH'] = iif(premake.config.isDebugBuild(cfg), 'YES', 'NO') + + -- build list of "other" C/C++ flags + local checks = { + ["-ffast-math"] = cfg.flags.FloatFast, + ["-ffloat-store"] = cfg.flags.FloatStrict, + ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, + } + + local flags = { } + for flag, check in pairs(checks) do + if check then + table.insert(flags, flag) + end + end + + + --[[if (type(cfg.buildoptions) == "table") then + for k,v in pairs(cfg.buildoptions) do + table.insertflat(flags, string.explode(v," -")) + end + end + ]] + + settings['OTHER_CFLAGS'] = table.join(flags, cfg.buildoptions) + + -- build list of "other" linked flags. All libraries that aren't frameworks + -- are listed here, so I don't have to try and figure out if they are ".a" + -- or ".dylib", which Xcode requires to list in the Frameworks section + flags = { } + for _, lib in ipairs(config.getlinks(cfg, "system")) do + if not xcode.isframework(lib) then + table.insert(flags, "-l" .. lib) + end + end + + --ms this step is for reference projects only + for _, lib in ipairs(config.getlinks(cfg, "dependencies", "object")) do + if (lib.external) then + if not xcode.isframework(lib.linktarget.basename) then + table.insert(flags, "-l" .. escapeArg(lib.linktarget.basename)) + end + end + end + + settings['OTHER_LDFLAGS'] = table.join(flags, cfg.linkoptions) + + if cfg.flags.StaticRuntime then + settings['STANDARD_C_PLUS_PLUS_LIBRARY_TYPE'] = 'static' + end + + if targetdir ~= "." then + settings['SYMROOT'] = path.getrelative(tr.project.location, targetdir) + end + + if cfg.warnings == "Extra" then + settings['WARNING_CFLAGS'] = '-Wall -Wextra' + end + + overrideSettings(settings, cfg.xcodebuildsettings) + + _p(2,'%s /* %s */ = {', cfg.xcode.projectid, cfg.buildcfg) + _p(3,'isa = XCBuildConfiguration;') + _p(3,'buildSettings = {') + printSettingsTable(4, settings) + _p(3,'};') + printSetting(3, 'name', cfg.buildcfg); + _p(2,'};') + end + + + function xcode.XCBuildConfiguration(tr) + local settings = {} + + for _, target in ipairs(tr.products.children) do + for _, cfg in ipairs(tr.configs) do + settings[cfg.xcode.targetid] = function() + xcode.XCBuildConfiguration_Target(tr, target, cfg) + end + end + end + for _, cfg in ipairs(tr.configs) do + settings[cfg.xcode.projectid] = function() + xcode.XCBuildConfiguration_Project(tr, cfg) + end + end + + if not table.isempty(settings) then + _p('/* Begin XCBuildConfiguration section */') + printSettingsTable(0, settings) + _p('/* End XCBuildConfiguration section */') + _p('') + end + end + + + function xcode.XCBuildConfigurationList(tr) + local wks = tr.project.workspace + local defaultCfgName = stringifySetting(tr.configs[1].buildcfg) + local settings = {} + + for _, target in ipairs(tr.products.children) do + settings[target.cfgsection] = function() + _p(2,'%s /* Build configuration list for PBXNativeTarget "%s" */ = {', target.cfgsection, target.name) + _p(3,'isa = XCConfigurationList;') + _p(3,'buildConfigurations = (') + for _, cfg in ipairs(tr.configs) do + _p(4,'%s /* %s */,', cfg.xcode.targetid, cfg.buildcfg) + end + _p(3,');') + _p(3,'defaultConfigurationIsVisible = 0;') + _p(3,'defaultConfigurationName = %s;', defaultCfgName) + _p(2,'};') + end + end + settings['1DEB928908733DD80010E9CD'] = function() + _p(2,'1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */ = {', tr.name) + _p(3,'isa = XCConfigurationList;') + _p(3,'buildConfigurations = (') + for _, cfg in ipairs(tr.configs) do + _p(4,'%s /* %s */,', cfg.xcode.projectid, cfg.buildcfg) + end + _p(3,');') + _p(3,'defaultConfigurationIsVisible = 0;') + _p(3,'defaultConfigurationName = %s;', defaultCfgName) + _p(2,'};') + end + + _p('/* Begin XCConfigurationList section */') + printSettingsTable(2, settings) + _p('/* End XCConfigurationList section */') + end diff --git a/modules/xcode/xcode_project.lua b/modules/xcode/xcode_project.lua new file mode 100644 index 00000000..e17ca579 --- /dev/null +++ b/modules/xcode/xcode_project.lua @@ -0,0 +1,200 @@ +--- +-- xcode/xcode4_project.lua +-- Generate an Xcode project file. +-- Author Jason Perkins +-- Modified by Mihai Sebea +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +--- + + local p = premake + local m = p.modules.xcode + + local xcode = p.modules.xcode + local project = p.project + local config = p.config + local fileconfig = p.fileconfig + local tree = p.tree + +-- +-- Create a tree corresponding to what is shown in the Xcode project browser +-- pane, with nodes for files and folders, resources, frameworks, and products. +-- +-- @param prj +-- The project being generated. +-- @returns +-- A tree, loaded with metadata, which mirrors Xcode's view of the project. +-- + + function xcode.buildprjtree(prj) + local tr = project.getsourcetree(prj, nil , false) + tr.project = prj + + -- create a list of build configurations and assign IDs + tr.configs = {} + + for cfg in project.eachconfig(prj) do + cfg.xcode = {} + cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode.name, cfg.buildcfg, "target") + cfg.xcode.projectid = xcode.newid(tr.name, cfg.buildcfg) + table.insert(tr.configs, cfg) + end + + -- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib) + -- to Xcode's display layout (MainMenu.xib/English). + tree.traverse(tr, { + onbranch = function(node) + if path.getextension(node.name) == ".lproj" then + local lang = path.getbasename(node.name) -- "English", "French", etc. + + -- create a new language group for each file it contains + for _, filenode in ipairs(node.children) do + local grpnode = node.parent.children[filenode.name] + if not grpnode then + grpnode = tree.insert(node.parent, tree.new(filenode.name)) + grpnode.kind = "vgroup" + end + + -- convert the file node to a language node and add to the group + filenode.name = path.getbasename(lang) + tree.insert(grpnode, filenode) + end + + -- remove this directory from the tree + tree.remove(node) + end + end + }) + + -- the special folder "Frameworks" lists all linked frameworks + tr.frameworks = tree.new("Frameworks") + for cfg in project.eachconfig(prj) do + for _, link in ipairs(config.getlinks(cfg, "system", "fullpath")) do + local name = path.getname(link) + if xcode.isframework(name) and not tr.frameworks.children[name] then + node = tree.insert(tr.frameworks, tree.new(name)) + node.path = link + end + end + end + + -- only add it to the tree if there are frameworks to link + if #tr.frameworks.children > 0 then + tree.insert(tr, tr.frameworks) + end + + -- the special folder "Products" holds the target produced by the project; this + -- is populated below + tr.products = tree.insert(tr, tree.new("Products")) + + -- the special folder "Projects" lists sibling project dependencies + tr.projects = tree.new("Projects") + for _, dep in ipairs(project.getdependencies(prj, "sibling", "object")) do + -- create a child node for the dependency's xcodeproj + local xcpath = xcode.getxcodeprojname(dep) + local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath))) + xcnode.path = xcpath + xcnode.project = dep + xcnode.productgroupid = xcode.newid(xcnode.name, "prodgrp") + xcnode.productproxyid = xcode.newid(xcnode.name, "prodprox") + xcnode.targetproxyid = xcode.newid(xcnode.name, "targprox") + xcnode.targetdependid = xcode.newid(xcnode.name, "targdep") + + -- create a grandchild node for the dependency's link target + local lprj = premake.workspace.findproject(prj.workspace, dep.name) + local cfg = project.findClosestMatch(lprj, prj.configurations[1]) + node = tree.insert(xcnode, tree.new(cfg.linktarget.name)) + node.path = cfg.linktarget.fullpath + node.cfg = cfg + end + + if #tr.projects.children > 0 then + tree.insert(tr, tr.projects) + end + + -- Final setup + tree.traverse(tr, { + onnode = function(node) + -- assign IDs to every node in the tree + node.id = xcode.newid(node.name, nil, node.path) + + node.isResource = xcode.isItemResource(prj, node) + + -- assign build IDs to buildable files + if xcode.getbuildcategory(node) then + node.buildid = xcode.newid(node.name, "build", node.path) + end + + -- remember key files that are needed elsewhere + if string.endswith(node.name, "Info.plist") then + tr.infoplist = node + end + end + }, true) + + -- Plug in the product node into the Products folder in the tree. The node + -- was built in xcode.prepareWorkspace() in xcode_common.lua; it contains IDs + -- that are necessary for inter-project dependencies + node = tree.insert(tr.products, prj.xcode.projectnode) + node.kind = "product" + node.path = node.cfg.buildtarget.fullpath + node.cfgsection = xcode.newid(node.name, "cfg") + node.resstageid = xcode.newid(node.name, "rez") + node.sourcesid = xcode.newid(node.name, "src") + node.fxstageid = xcode.newid(node.name, "fxs") + + return tr + end + + +--- +-- Generate an Xcode .xcodeproj for a Premake project. +--- + + m.elements.project = function(prj) + return { + m.header, + } + end + + function m.generateProject(prj) + local tr = xcode.buildprjtree(prj) + p.callArray(m.elements.project, prj) + xcode.PBXBuildFile(tr) + xcode.PBXContainerItemProxy(tr) + xcode.PBXFileReference(tr) + xcode.PBXFrameworksBuildPhase(tr) + xcode.PBXGroup(tr) + xcode.PBXNativeTarget(tr) + xcode.PBXProject(tr) + xcode.PBXReferenceProxy(tr) + xcode.PBXResourcesBuildPhase(tr) + xcode.PBXShellScriptBuildPhase(tr) + xcode.PBXSourcesBuildPhase(tr) + xcode.PBXTargetDependency(tr) + xcode.PBXVariantGroup(tr) + xcode.XCBuildConfiguration(tr) + xcode.XCBuildConfigurationList(tr) + xcode.footer(prj) + end + + + + function m.header(prj) + p.w('// !$*UTF8*$!') + p.push('{') + p.w('archiveVersion = 1;') + p.w('classes = {') + p.w('};') + p.w('objectVersion = 46;') + p.push('objects = {') + p.w() + end + + + + function xcode.footer(prj) + p.pop('};') + p.w('rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;') + p.pop('}') + end + diff --git a/scripts/RELEASE.txt b/scripts/RELEASE.txt index 14252f0e..35c44bea 100644 --- a/scripts/RELEASE.txt +++ b/scripts/RELEASE.txt @@ -9,7 +9,7 @@ PREP * Update CHANGES.txt and CONTRIBUTORS.txt - * Update version in src/host/premake.c and commit + * Update version in src/host/premake.h and commit * Push release branch to GitHub; wait for CI to pass diff --git a/src/_modules.lua b/src/_modules.lua index 792833df..f809c097 100644 --- a/src/_modules.lua +++ b/src/_modules.lua @@ -6,7 +6,6 @@ return { "xcode", - "monodevelop", "codelite", "d", } diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 44df506d..0402a721 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -845,6 +845,7 @@ kind = "list:string", tokens = true, pathVars = true, + allowDuplicates = true, } api.register { @@ -861,6 +862,7 @@ kind = "list:string", tokens = true, pathVars = true, + allowDuplicates = true, } api.register { @@ -1494,4 +1496,7 @@ filter { "kind:SharedLib", "system:not Windows" } pic "On" + filter { "system:macosx" } + toolset "clang" + filter {} diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index b445d328..adb3da0b 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -410,7 +410,7 @@ function make.forceInclude(cfg, toolset) local includes = toolset.getforceincludes(cfg) if not cfg.flags.NoPCH and cfg.pchheader then - table.insert(includes, "-include $(OBJDIR)/$(notdir $(PCH))") + table.insert(includes, 1, "-include $(OBJDIR)/$(notdir $(PCH))") end _x(' FORCE_INCLUDE +=%s', make.list(includes)) end @@ -445,7 +445,7 @@ if cfg.architecture == premake.UNIVERSAL then _p(' LINKCMD = libtool -o "$@" $(OBJECTS)') else - _p(' LINKCMD = $(AR) -rcs "$@" $(OBJECTS)') + _p(' LINKCMD = $(AR) ' .. (toolset.arargs or '-rcs') ..' "$@" $(OBJECTS)') end elseif cfg.kind == premake.UTILITY then -- Empty LINKCMD for Utility (only custom build rules) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 1c169614..2d6a41bd 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -237,6 +237,8 @@ m.nmakeCommandLine(cfg, cfg.buildcommands, "Build") m.nmakeCommandLine(cfg, cfg.rebuildcommands, "ReBuild") m.nmakeCommandLine(cfg, cfg.cleancommands, "Clean") + m.nmakePreprocessorDefinitions(cfg, cfg.defines, false, nil) + m.nmakeIncludeDirs(cfg, cfg.includedirs) p.pop('') end end @@ -308,7 +310,6 @@ m.clCompileAdditionalUsingDirectories, m.forceIncludes, m.debugInformationFormat, - m.programDataBaseFileName, m.optimization, m.functionLevelLinking, m.intrinsicFunctions, @@ -409,6 +410,7 @@ m.largeAddressAware, m.targetMachine, m.additionalLinkOptions, + m.programDatabaseFile, } end end @@ -431,6 +433,8 @@ m.elements.lib = function(cfg, explicit) if cfg.kind == p.STATICLIB then return { + m.additionalDependencies, + m.additionalLibraryDirectories, m.treatLinkerWarningAsErrors, m.targetMachine, m.additionalLinkOptions, @@ -1177,10 +1181,10 @@ function m.debugInformationFormat(cfg) local value local tool, toolVersion = p.config.toolset(cfg) - if cfg.symbols == p.ON then + if (cfg.symbols == p.ON) or (cfg.symbols == "FastLink") then if cfg.debugformat == "c7" then value = "OldStyle" - elseif cfg.architecture == "x86_64" or + elseif (cfg.architecture == "x86_64" and _ACTION < "vs2015") or cfg.clr ~= p.OFF or config.isOptimizedBuild(cfg) or cfg.editandcontinue == p.OFF or @@ -1669,7 +1673,25 @@ m.element("NMakeOutput", nil, "$(OutDir)%s", cfg.buildtarget.name) end + function m.nmakePreprocessorDefinitions(cfg, defines, escapeQuotes, condition) + if #defines > 0 then + defines = table.concat(defines, ";") + if escapeQuotes then + defines = defines:gsub('"', '\\"') + end + defines = p.esc(defines) .. ";$(NMakePreprocessorDefinitions)" + m.element('NMakePreprocessorDefinitions', condition, defines) + end + end + function m.nmakeIncludeDirs(cfg, includedirs) + if #includedirs > 0 then + local dirs = vstudio.path(cfg, includedirs) + if #dirs > 0 then + m.element("NMakeIncludeSearchPath", nil, "%s", table.concat(dirs, ";")) + end + end + end function m.objectFileName(fcfg) if fcfg.objname ~= fcfg.basename then @@ -1793,9 +1815,9 @@ end - function m.programDataBaseFileName(cfg) + function m.programDatabaseFile(cfg) if cfg.symbolspath and cfg.symbols == p.ON and cfg.debugformat ~= "c7" then - m.element("ProgramDataBaseFileName", nil, p.project.getrelative(cfg.project, cfg.symbolspath)) + m.element("ProgramDatabaseFile", nil, p.project.getrelative(cfg.project, cfg.symbolspath)) end end diff --git a/src/base/api.lua b/src/base/api.lua index b07dc2a5..f4f251ce 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -903,8 +903,8 @@ -- contain any other kind of data. --- - local function storeListItem(current, item) - if current[item] then + local function storeListItem(current, item, allowDuplicates) + if not allowDuplicates and current[item] then table.remove(current, table.indexof(current, item)) end table.insert(current, item) @@ -937,13 +937,13 @@ if type(value) == "table" then if #value > 0 then for i = 1, #value do - storeListItem(current, value[i]) + storeListItem(current, value[i], field.allowDuplicates) end elseif not table.isempty(value) then - storeListItem(current, value) + storeListItem(current, value, field.allowDuplicates) end elseif value then - storeListItem(current, value) + storeListItem(current, value, field.allowDuplicates) end return current @@ -953,7 +953,7 @@ local function mergeList(field, current, value, processor) value = value or {} for i = 1, #value do - storeListItem(current, value[i]) + storeListItem(current, value[i], field.allowDuplicates) end return current end diff --git a/src/host/os_copyfile.c b/src/host/os_copyfile.c index 6d3a82e3..526afb5c 100644 --- a/src/host/os_copyfile.c +++ b/src/host/os_copyfile.c @@ -16,7 +16,7 @@ int os_copyfile(lua_State* L) #if PLATFORM_WINDOWS z = CopyFileA(src, dst, FALSE); #else - lua_pushfstring(L, "cp %s %s", src, dst); + lua_pushfstring(L, "cp \"%s\" \"%s\"", src, dst); z = (system(lua_tostring(L, -1)) == 0); #endif diff --git a/src/host/path_isabsolute.c b/src/host/path_isabsolute.c index a324b7f3..6995fbe9 100644 --- a/src/host/path_isabsolute.c +++ b/src/host/path_isabsolute.c @@ -26,7 +26,7 @@ int do_isabsolute(const char* path) return 1; if (isalpha(path[0]) && path[1] == ':') return 1; - if (path[0] == '"') + if (path[0] == '"' || path[0] == '!') return do_isabsolute(path + 1); // $(foo) and %(foo) diff --git a/tests/actions/vstudio/vc2010/test_build_events.lua b/tests/actions/vstudio/vc2010/test_build_events.lua index 1efed369..3662ef99 100644 --- a/tests/actions/vstudio/vc2010/test_build_events.lua +++ b/tests/actions/vstudio/vc2010/test_build_events.lua @@ -85,6 +85,17 @@ end +-- +-- Multiple of the same command should be emit. +-- + + function suite.onCommandTwice() + postbuildcommands { "command", "command" } + prepare() + test.capture ("\n\tcommand\r\ncommand\n\n") + end + + -- -- Quotes should not be escaped, other special characters should. diff --git a/tests/actions/vstudio/vc2010/test_compile_settings.lua b/tests/actions/vstudio/vc2010/test_compile_settings.lua index c6f1b568..ff9b4cd7 100644 --- a/tests/actions/vstudio/vc2010/test_compile_settings.lua +++ b/tests/actions/vstudio/vc2010/test_compile_settings.lua @@ -621,6 +621,22 @@ ]] end +-- +-- Check the handling of the editandcontinue flag. +-- + + function suite.debugFormat_onFastLinkBuild() + symbols "FastLink" + editandcontinue "Off" + prepare() + test.capture [[ + + NotUsing + Level3 + ProgramDatabase + ]] + end + -- -- Edit-and-Continue is not supported for optimized builds. @@ -639,6 +655,7 @@ end + -- -- Edit-and-Continue is not supported for Managed builds. -- diff --git a/tests/actions/vstudio/vc2010/test_link.lua b/tests/actions/vstudio/vc2010/test_link.lua index 2da8d427..7955f84e 100644 --- a/tests/actions/vstudio/vc2010/test_link.lua +++ b/tests/actions/vstudio/vc2010/test_link.lua @@ -155,6 +155,20 @@ ]] end + function suite.additionalDependencies_onSystemLinksStatic() + kind "StaticLib" + links { "lua", "zlib" } + prepare() + test.capture [[ + + Windows + + + lua.lib;zlib.lib;%(AdditionalDependencies) + + ]] + end + -- -- Any system libraries specified in links() with valid extensions should @@ -171,6 +185,20 @@ ]] end + function suite.additionalDependencies_onSystemLinksExtensionsStatic() + kind "StaticLib" + links { "lua.obj", "zlib.lib" } + prepare() + test.capture [[ + + Windows + + + lua.obj;zlib.lib;%(AdditionalDependencies) + + ]] + end + -- -- Any system libraries specified in links() with multiple dots should @@ -187,6 +215,20 @@ ]] end + function suite.additionalDependencies_onSystemLinksExtensionsMultipleDotsStatic() + kind "StaticLib" + links { "lua.5.3.lib", "lua.5.4" } + prepare() + test.capture [[ + + Windows + + + lua.5.3.lib;lua.5.4.lib;%(AdditionalDependencies) + + ]] + end + -- -- Additional library directories should be specified, relative to the project. diff --git a/tests/actions/vstudio/vc2010/test_nmake_props.lua b/tests/actions/vstudio/vc2010/test_nmake_props.lua index b0b60b81..a88e3d81 100644 --- a/tests/actions/vstudio/vc2010/test_nmake_props.lua +++ b/tests/actions/vstudio/vc2010/test_nmake_props.lua @@ -114,3 +114,25 @@ command 2 ]] end + + function suite.onDefines() + defines { "DEBUG", "_DEBUG" } + prepare() + test.capture [[ + + $(OutDir)MyProject + DEBUG;_DEBUG;$(NMakePreprocessorDefinitions) + + ]] + end + + function suite.onIncludeDirs() + includedirs { "include/lua", "include/zlib" } + prepare() + test.capture [[ + + $(OutDir)MyProject + include\lua;include\zlib + + ]] + end diff --git a/tests/base/.testDotFile b/tests/base/.testDotFile new file mode 100644 index 00000000..b9928548 --- /dev/null +++ b/tests/base/.testDotFile @@ -0,0 +1 @@ +This is a test file for os.matchfiles tests. diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index 50e628f0..7b154746 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -105,8 +105,8 @@ end function suite.matchfiles_OnDottedFile() - local result = os.matchfiles("../.*") - test.istrue(table.contains(result, "../.gitignore")) + local result = os.matchfiles("base/.*") + test.istrue(table.contains(result, "base/.testDotFile")) end function suite.matchfiles_onComboSearch() diff --git a/tests/oven/test_objdirs.lua b/tests/oven/test_objdirs.lua index 51e60048..0fad6620 100644 --- a/tests/oven/test_objdirs.lua +++ b/tests/oven/test_objdirs.lua @@ -14,73 +14,70 @@ local wks, prj function suite.setup() - end - - local function result(buildcfg, platform) - local cfg = test.getconfig(prj, buildcfg, platform) - return path.getrelative(os.getcwd(), cfg.objdir) - end - - - - function suite.singleProject_noPlatforms() wks = workspace("MyWorkspace") configurations { "Debug", "Release" } prj = project "MyProject" + end - test.isequal("obj/Debug", result("Debug")) - test.isequal("obj/Release", result("Release")) + local function prepare(buildcfg, platform) + cfg = test.getconfig(prj, buildcfg, platform) + end + + function suite.singleProject_noPlatforms() + prepare("Debug") + test.isequal(path.getabsolute("obj/Debug"), cfg.objdir) + + prepare("Release") + test.isequal(path.getabsolute("obj/Release"), cfg.objdir) end function suite.multipleProjects_noPlatforms() - wks = workspace("MyWorkspace") - configurations { "Debug", "Release" } - prj = project "MyProject" project "MyProject2" + prepare("Debug") test.createproject(wks) - test.isequal("obj/Debug/MyProject", result("Debug")) + test.isequal(path.getabsolute("obj/Debug/MyProject"), cfg.objdir) end function suite.singleProject_withPlatforms() - wks = workspace("MyWorkspace") - configurations { "Debug", "Release" } platforms { "x86", "x86_64" } - prj = project "MyProject" + prepare("Debug", "x86") - test.isequal("obj/x86/Debug", result("Debug", "x86")) + test.isequal(path.getabsolute("obj/x86/Debug"), cfg.objdir) end function suite.singleProject_uniqueByTokens_noPlatforms() - wks = workspace("MyWorkspace") - configurations { "Debug", "Release" } - prj = project "MyProject" objdir "obj/%{cfg.buildcfg}" + prepare("Debug") - test.isequal("obj/Debug", result("Debug")) + test.isequal(path.getabsolute("obj/Debug"), cfg.objdir) end function suite.singleProject_uniqueByTokens_withPlatforms() - wks = workspace("MyWorkspace") - configurations { "Debug", "Release" } platforms { "x86", "x86_64" } - prj = project "MyProject" objdir "obj/%{cfg.buildcfg}_%{cfg.platform}" + prepare("Debug", "x86") - test.isequal("obj/Debug_x86", result("Debug", "x86")) + test.isequal(path.getabsolute("obj/Debug_x86"), cfg.objdir) end function suite.allowOverlap_onPrefixCode() - wks = workspace("MyWorkspace") - configurations { "Debug", "Release" } platforms { "x86", "x86_64" } - prj = project "MyProject" objdir "!obj/%{cfg.buildcfg}" + prepare("Debug", "x86") - test.isequal("obj/Debug", result("Debug", "x86")) + test.isequal(path.getabsolute("obj/Debug"), cfg.objdir) + end + + function suite.allowOverlap_onPrefixCode_withEnvironmentVariable() + platforms { "x86", "x86_64" } + objdir "!$(SolutionDir)/%{cfg.buildcfg}" + prepare("Debug", "x86") + + test.isequal("$(SolutionDir)/Debug", cfg.objdir) end