diff --git a/.hgsubstate b/.hgsubstate index 83a0246f..fd45a1d5 100644 --- a/.hgsubstate +++ b/.hgsubstate @@ -1 +1 @@ -3935627f6ef6f848afd1ac3b22cc1eaa7b34a582 modules/xcode +44e7630091915c687ded94b1bce64d61573cf833 modules/xcode diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 1237033b..095cfde6 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -13,5 +13,10 @@ Builds and Infrastructure: * Nightly Jenkins builds and error reports Patch contributors: - noresources + Manu Evans + * new APIs for debugging, controlling warnings, undefining symbols + Mihai Sebea + * Xcode exporter fixes and improvements + Renaud Guillard * add library search paths argument to os.findlib() + * return command exit code from os.outputof() diff --git a/scripts/embed.lua b/scripts/embed.lua index 01de3580..23c61b65 100644 --- a/scripts/embed.lua +++ b/scripts/embed.lua @@ -7,6 +7,7 @@ local function loadScript(fname) + fname = path.getabsolute(fname) local f = io.open(fname) local s = assert(f:read("*a")) f:close() diff --git a/src/_manifest.lua b/src/_manifest.lua index 4831f3f3..46c74f9a 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -85,4 +85,8 @@ "actions/clean/_clean.lua", "_premake_init.lua", + + -- Built-in action modules. The action is registered, but the actual + -- implementation is not loaded unless the action is used. + "../modules/xcode/_action.lua", } diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 3d8dfb49..6adca06e 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -202,6 +202,13 @@ pathVars = true, } + api.register { + name = "debugconnectcommands", + scope = "config", + kind = "list:string", + tokens = true, + } + api.register { name = "debugdir", scope = "config", @@ -218,6 +225,12 @@ pathVars = true, } + api.register { + name = "debugextendedprotocol", + scope = "config", + kind = "boolean", + } + api.register { name = "debugformat", scope = "config", @@ -227,6 +240,33 @@ }, } + api.register { + name = "debugport", + scope = "config", + kind = "integer", + } + + api.register { + name = "debugremotehost", + scope = "config", + kind = "string", + tokens = true, + } + + api.register { + name = "debugsearchpaths", + scope = "config", + kind = "list:path", + tokens = true, + } + + api.register { + name = "debugstartupcommands", + scope = "config", + kind = "list:string", + tokens = true, + } + api.register { name = "defaultplatform", scope = "project", @@ -255,6 +295,14 @@ } + api.register { + name = "disablewarnings", + scope = "config", + kind = "list:string", + tokens = true, + } + + api.register { name = "display", scope = "rule", @@ -269,12 +317,28 @@ } + api.register { + name = "enablewarnings", + scope = "config", + kind = "list:string", + tokens = true, + } + + -- For backward compatibility, excludes() is now an alias for removefiles() function excludes(value) removefiles(value) end + api.register { + name = "fatalwarnings", + scope = "config", + kind = "list:string", + tokens = true, + } + + api.register { name = "fileExtension", scope = "rule", @@ -388,6 +452,13 @@ kind = "string", } + api.register { + name = "gccprefix", + scope = "config", + kind = "string", + tokens = true, + } + api.register { name = "icon", scope = "project", @@ -750,6 +821,13 @@ end, } + api.register { + name = "undefines", + scope = "config", + kind = "list:string", + tokens = true, + } + api.register { name = "usingdirs", scope = "config", @@ -809,7 +887,6 @@ } - ----------------------------------------------------------------------------- -- -- Handlers for deprecated fields and values. diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 8774c18e..a9802d03 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -380,7 +380,7 @@ function make.defines(cfg, toolset) - _p(' DEFINES +=%s', make.list(toolset.getdefines(cfg.defines))) + _p(' DEFINES +=%s', make.list(table.join(toolset.getdefines(cfg.defines), toolset.getundefines(cfg.undefines)))) end diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index b687a277..bb5f30fb 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -460,6 +460,7 @@ m.additionalIncludeDirectories, m.wholeProgramOptimization, m.preprocessorDefinitions, + m.undefinePreprocessorDefinitions, m.minimalRebuild, m.basicRuntimeChecks, m.bufferSecurityCheck, @@ -478,6 +479,7 @@ m.detect64BitPortabilityProblems, m.debugInformationFormat, m.compileAs, + m.disableSpecificWarnings, m.forcedIncludeFiles, m.omitDefaultLib, } @@ -487,6 +489,7 @@ m.additionalExternalCompilerOptions, m.additionalIncludeDirectories, m.preprocessorDefinitions, + m.undefinePreprocessorDefinitions, m.usePrecompiledHeader, m.programDataBaseFileName, m.debugInformationFormat, @@ -623,6 +626,7 @@ m.cleanCommandLine, m.output, m.preprocessorDefinitions, + m.undefinePreprocessorDefinitions, m.includeSearchPath, m.forcedIncludes, m.assemblySearchPath, @@ -1001,6 +1005,14 @@ + function m.disableSpecificWarnings(cfg) + if #cfg.disablewarnings > 0 then + p.x('DisableSpecificWarnings="%s"', table.concat(cfg.disablewarnings, ";")) + end + end + + + function m.compileAsManaged(cfg) p.w('CompileAsManaged=""') end @@ -1393,6 +1405,12 @@ end + function m.undefinePreprocessorDefinitions(cfg) + if #cfg.undefines > 0 then + p.x('UndefinePreprocessorDefinitions="%s"', table.concat(cfg.undefines, ";")) + end + end + function m.programDatabaseFile(cfg, toolset) if toolset then diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 6e39af28..e75a39d4 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -291,8 +291,11 @@ m.precompiledHeader, m.warningLevel, m.treatWarningAsError, + m.disableSpecificWarnings, + m.treatSpecificWarningsAsErrors, m.basicRuntimeChecks, m.clCompilePreprocessorDefinitions, + m.clCompileUndefinePreprocessorDefinitions, m.clCompileAdditionalIncludeDirectories, m.clCompileAdditionalUsingDirectories, m.forceIncludes, @@ -605,11 +608,14 @@ local condition = m.condition(cfg) m.objectFileName(fcfg) m.clCompilePreprocessorDefinitions(fcfg, condition) + m.clCompileUndefinePreprocessorDefinitions(fcfg, condition) m.optimization(fcfg, condition) m.forceIncludes(fcfg, condition) m.precompiledHeader(cfg, fcfg, condition) m.enableEnhancedInstructionSet(fcfg, condition) m.additionalCompileOptions(fcfg, condition) + m.disableSpecificWarnings(fcfg, condition) + m.treatSpecificWarningsAsErrors(fcfg, condition) end end p.pop() @@ -961,6 +967,11 @@ end + function m.clCompileUndefinePreprocessorDefinitions(cfg, condition) + m.undefinePreprocessorDefinitions(cfg, cfg.undefines, false, condition) + end + + function m.clrSupport(cfg) local value if cfg.clr == "On" or cfg.clr == "Unsafe" then @@ -1429,6 +1440,18 @@ end + function m.undefinePreprocessorDefinitions(cfg, undefines, escapeQuotes, condition) + if #undefines > 0 then + undefines = table.concat(undefines, ";") + if escapeQuotes then + undefines = undefines:gsub('"', '\\"') + end + undefines = premake.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)" + m.element('UndefinePreprocessorDefinitions', condition, undefines) + end + end + + function m.programDataBaseFileName(cfg) -- just a placeholder for overriding; will use the default VS name end @@ -1595,6 +1618,24 @@ end + function m.disableSpecificWarnings(cfg, condition) + if #cfg.disablewarnings > 0 then + local warnings = table.concat(cfg.disablewarnings, ";") + warnings = premake.esc(warnings) .. ";%%(DisableSpecificWarnings)" + m.element('DisableSpecificWarnings', condition, warnings) + end + end + + + function m.treatSpecificWarningsAsErrors(cfg, condition) + if #cfg.fatalwarnings > 0 then + local fatal = table.concat(cfg.fatalwarnings, ";") + fatal = premake.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)" + m.element('TreatSpecificWarningsAsErrors', condition, fatal) + end + end + + function m.useDebugLibraries(cfg) local runtime = config.getruntime(cfg) _p(2,'%s', tostring(runtime:endswith("Debug"))) diff --git a/src/base/action.lua b/src/base/action.lua index df5dec27..a6e45d65 100644 --- a/src/base/action.lua +++ b/src/base/action.lua @@ -197,6 +197,11 @@ if act then _OS = act.os or _OS end + + -- Some are implemented in standalone modules + if act and act.module then + require(act.module) + end end diff --git a/src/base/os.lua b/src/base/os.lua index 7015d494..0fb493d4 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -387,9 +387,12 @@ local pipe = io.popen(cmd) local result = pipe:read('*a') - pipe:close() + local b, exitcode = pipe:close() + if not b then + exitcode = -1 + end - return result + return result, exitcode end diff --git a/src/host/lua-5.1.4/src/liolib.c b/src/host/lua-5.1.4/src/liolib.c index e79ed1cb..ca9f9844 100644 --- a/src/host/lua-5.1.4/src/liolib.c +++ b/src/host/lua-5.1.4/src/liolib.c @@ -105,11 +105,27 @@ static int io_noclose (lua_State *L) { /* ** function to close 'popen' files */ +/* + * PREMAKE change: return both output and exit code + */ static int io_pclose (lua_State *L) { FILE **p = tofilep(L); - int ok = lua_pclose(L, *p); + int result = lua_pclose(L, *p); *p = NULL; - return pushresult(L, ok, NULL); + if (result == -1) { + /* + * pclose call failure + */ + return pushresult(L, 0, NULL); + } + lua_pushboolean(L, 1); + /** + * On success, pcluse returns a 2 byte length integer + * where the higher byte contains the command exit code + */ + result /= 255; + lua_pushinteger(L, result); + return 2; } diff --git a/src/host/lua-5.1.4/src/luaconf.h b/src/host/lua-5.1.4/src/luaconf.h index e2cb2616..c3775903 100644 --- a/src/host/lua-5.1.4/src/luaconf.h +++ b/src/host/lua-5.1.4/src/luaconf.h @@ -668,12 +668,18 @@ union luai_Cast { double l_d; long l_l; }; #if defined(LUA_USE_POPEN) #define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) +/* + * PREMAKE change: get pclose return value + */ +#define lua_pclose(L,file) ((void)L, (pclose(file))) #elif defined(LUA_WIN) #define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) +/* + * PREMAKE change: get pclose return value + */ +#define lua_pclose(L,file) ((void)L, (_pclose(file))) #else diff --git a/src/tools/clang.lua b/src/tools/clang.lua index 5a8df4ee..d6d7df2c 100644 --- a/src/tools/clang.lua +++ b/src/tools/clang.lua @@ -89,6 +89,14 @@ end + function clang.getundefines(undefines) + + -- Just pass through to GCC for now + local flags = gcc.getundefines(undefines) + return flags + + end + -- diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index 4142ca8f..8ee93ea2 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -80,9 +80,24 @@ function gcc.getcflags(cfg) local flags = config.mapFlags(cfg, gcc.cflags) + flags = table.join(flags, gcc.getwarnings(cfg)) return flags end + function gcc.getwarnings(cfg) + local result = {} + for _, enable in ipairs(cfg.enablewarnings) do + table.insert(result, '-W' .. enable) + end + for _, disable in ipairs(cfg.disablewarnings) do + table.insert(result, '-Wno-' .. disable) + end + for _, fatal in ipairs(cfg.fatalwarnings) do + table.insert(result, '-Werror=' .. fatal) + end + return result + end + -- -- Returns list of C++ compiler flags for a configuration. @@ -114,6 +129,14 @@ return result end + function gcc.getundefines(undefines) + local result = {} + for _, undefine in ipairs(undefines) do + table.insert(result, '-U' .. undefine) + end + return result + end + -- -- Returns a list of forced include files, decorated for the compiler @@ -285,14 +308,18 @@ -- gcc.tools = { + cc = "gcc", + cxx = "g++", + ar = "ar", + rc = "windres" } function gcc.gettoolname(cfg, tool) local names = gcc.tools[cfg.architecture] or gcc.tools[cfg.system] or {} local name = names[tool] - if tool == "rc" then - name = name or "windres" + if not name and (tool == "rc" or cfg.gccprefix) and gcc.tools[tool] then + name = (cfg.gccprefix or "") .. gcc.tools[tool] end return name diff --git a/src/tools/msc.lua b/src/tools/msc.lua index 5ef1a079..e6dd707b 100644 --- a/src/tools/msc.lua +++ b/src/tools/msc.lua @@ -66,6 +66,8 @@ function msc.getcflags(cfg) local flags = config.mapFlags(cfg, msc.cflags) + flags = table.join(flags, msc.getwarnings(cfg)) + local runtime = iif(cfg.flags.StaticRuntime, "/MT", "/MD") if config.isDebugBuild(cfg) then runtime = runtime .. "d" @@ -75,6 +77,18 @@ return flags end + function msc.getwarnings(cfg) + local result = {} + -- NOTE: VStudio can't enable specific warnings (workaround?) + for _, disable in ipairs(cfg.disablewarnings) do + table.insert(result, '/wd"' .. disable .. '"') + end + for _, fatal in ipairs(cfg.fatalwarnings) do + table.insert(result, '/we"' .. fatal .. '"') + end + return result + end + -- -- Returns list of C++ compiler flags for a configuration. @@ -104,7 +118,15 @@ function msc.getdefines(defines) local result = {} for _, define in ipairs(defines) do - table.insert(result, '-D' .. define) + table.insert(result, '/D"' .. define .. '"') + end + return result + end + + function msc.getundefines(undefines) + local result = {} + for _, undefine in ipairs(undefines) do + table.insert(result, '/U"' .. undefine .. '"') end return result end diff --git a/tests/actions/make/solution/test_group_rule.lua b/tests/actions/make/solution/test_group_rule.lua index af956042..c084ad7f 100644 --- a/tests/actions/make/solution/test_group_rule.lua +++ b/tests/actions/make/solution/test_group_rule.lua @@ -36,18 +36,18 @@ -- function suite.groupRule_groupAsPhony() - prepare() + prepare() make.solutionPhonyRule(sln) test.capture [[ .PHONY: all clean help $(PROJECTS) MainGroup MainGroup/SubGroup1 MainGroup/SubGroup2 ]] end - + -- -- Transform solution groups into target aggregate -- function suite.groupRule_groupRules() - prepare() + prepare() make.groupRules(sln) test.capture [[ MainGroup: MainGroup/SubGroup1 MainGroup/SubGroup2 MyProject2 diff --git a/tests/actions/vstudio/vc2010/test_compile_settings.lua b/tests/actions/vstudio/vc2010/test_compile_settings.lua index de25bbec..792775f9 100644 --- a/tests/actions/vstudio/vc2010/test_compile_settings.lua +++ b/tests/actions/vstudio/vc2010/test_compile_settings.lua @@ -119,6 +119,36 @@ ]] end +-- +-- Disable specific warnings. +-- + + function suite.disableSpecificWarnings() + disablewarnings { "disable" } + prepare() + test.capture [[ + + NotUsing + Level3 + disable;%(DisableSpecificWarnings) + ]] + end + +-- +-- Specific warnings as errors. +-- + + function suite.specificWarningsAsErrors() + fatalwarnings { "fatal" } + prepare() + test.capture [[ + + NotUsing + Level3 + fatal;%(TreatSpecificWarningsAsErrors) + ]] + end + -- -- Check the optimization flags. -- @@ -236,6 +266,22 @@ end +-- +-- If undefines are specified, the element should be added. +-- + + function suite.preprocessorDefinitions_onUnDefines() + undefines { "DEBUG", "_DEBUG" } + prepare() + test.capture [[ + + NotUsing + Level3 + DEBUG;_DEBUG;%(UndefinePreprocessorDefinitions) + ]] + end + + -- -- If build options are specified, the element should be specified. -- diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index 2d506cd6..ed0c319a 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -132,6 +132,32 @@ end +-- +-- os.outputof() tests +-- + + -- Check if outputof returns the command exit code + -- in addition of the command output + function suite.outputof_commandExitCode() + if os.is("macosx") + or os.is("linux") + or os.is("solaris") + or os.is("bsd") + then + -- Assumes 'true' and 'false' commands exist + -- which should be the case on all *nix platforms + for cmd, exitcode in pairs ({ + ["true"] = 0, + ["false"] = 1 + }) + do + local o, e = os.outputof(cmd) + test.isequal(e, exitcode) + end + end + end + + -- -- os.translateCommand() tests -- @@ -145,4 +171,4 @@ copy = function(value) return "test " .. value end } test.isequal("test a b", os.translateCommands("{COPY} a b", "test")) - end \ No newline at end of file + end diff --git a/tests/tools/test_gcc.lua b/tests/tools/test_gcc.lua index fd66cafb..e32782f9 100644 --- a/tests/tools/test_gcc.lua +++ b/tests/tools/test_gcc.lua @@ -38,6 +38,15 @@ test.isequal("windres", gcc.gettoolname(cfg, "rc")) end + function suite.tools_withPrefix() + gccprefix "test-prefix-" + prepare() + test.isequal("test-prefix-gcc", gcc.gettoolname(cfg, "cc")) + test.isequal("test-prefix-g++", gcc.gettoolname(cfg, "cxx")) + test.isequal("test-prefix-ar", gcc.gettoolname(cfg, "ar")) + test.isequal("test-prefix-windres", gcc.gettoolname(cfg, "rc")) + end + -- -- By default, the -MMD -MP are used to generate dependencies. @@ -76,6 +85,14 @@ test.contains({ "-Werror" }, gcc.getcflags(cfg)) end + function suite.cflags_onSpecificWarnings() + enablewarnings { "enable" } + disablewarnings { "disable" } + fatalwarnings { "fatal" } + prepare() + test.contains({ "-Wenable", "-Wno-disable", "-Werror=fatal" }, gcc.getcflags(cfg)) + end + function suite.cflags_onFloastFast() floatingpoint "Fast" prepare() @@ -107,6 +124,23 @@ end +-- +-- Check the defines and undefines. +-- + + function suite.defines() + defines "DEF" + prepare() + test.contains({ "-DDEF" }, gcc.getdefines(cfg.defines)) + end + + function suite.undefines() + undefines "UNDEF" + prepare() + test.contains({ "-UUNDEF" }, gcc.getundefines(cfg.undefines)) + end + + -- -- Check the optimization flags. -- diff --git a/tests/tools/test_msc.lua b/tests/tools/test_msc.lua index 7f09c697..5a4e0ce9 100644 --- a/tests/tools/test_msc.lua +++ b/tests/tools/test_msc.lua @@ -111,6 +111,14 @@ test.contains("/WX", msc.getcflags(cfg)) end + function suite.cflags_onSpecificWarnings() + enablewarnings { "enable" } + disablewarnings { "disable" } + fatalwarnings { "fatal" } + prepare() + test.contains({ '/wd"disable"', '/we"fatal"' }, msc.getcflags(cfg)) + end + function suite.ldflags_OnFatalWarnings() flags "FatalWarnings" prepare() @@ -169,6 +177,23 @@ end +-- +-- Check the defines and undefines. +-- + + function suite.defines() + defines "DEF" + prepare() + test.contains({ '/D"DEF"' }, msc.getdefines(cfg.defines)) + end + + function suite.undefines() + undefines "UNDEF" + prepare() + test.contains({ '/U"UNDEF"' }, msc.getundefines(cfg.undefines)) + end + + -- -- Check compilation options. --