diff --git a/src/_manifest.lua b/src/_manifest.lua index 2f1113b6..b0311bfe 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -41,7 +41,7 @@ "base/project.lua", "base/config.lua", "base/fileconfig.lua", - "base/rules.lua", + "base/rule.lua", -- project script processing "base/oven.lua", diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 8d149b42..9dbfc99d 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -130,18 +130,35 @@ tokens = true, } + api.register { name = "cleanExtensions", scope = "config", kind = "list:string", } + + api.register { + name = "clr", + scope = "config", + kind = "string", + allowed = { + "Off", + "On", + "Pure", + "Safe", + "Unsafe", + } + } + + api.register { name = "configmap", scope = "config", kind = "list:keyed:array:string", } + api.register { name = "configFile", scope = "config", @@ -162,13 +179,6 @@ tokens = true, } - api.register { - name = "customRules", - scope = "project", - kind = "list:file", - tokens = true, - } - api.register { name = "debugargs", scope = "config", @@ -241,6 +251,13 @@ } + api.register { + name = "editAndContinue", + scope = "config", + kind = "boolean", + } + + -- For backward compatibility, excludes() is now an alias for removefiles() function excludes(value) removefiles(value) @@ -285,14 +302,14 @@ "FloatFast", -- DEPRECATED "FloatStrict", -- DEPRECATED "LinkTimeOptimization", - "Managed", + "Managed", -- DEPRECATED "Maps", "MFC", "MultiProcessorCompile", "NativeWChar", -- DEPRECATED "No64BitChecks", "NoCopyLocal", - "NoEditAndContinue", + "NoEditAndContinue", -- DEPRECATED "NoExceptions", "NoFramePointer", "NoImplicitLink", @@ -312,10 +329,12 @@ "OptimizeSpeed", -- DEPRECATED "ReleaseRuntime", "SEH", + "ShadowedVariables", "StaticRuntime", "Symbols", + "UndefinedIdentifiers", "Unicode", - "Unsafe", + "Unsafe", -- DEPRECATED "WinMain", "WPF", }, @@ -624,6 +643,12 @@ tokens = true, } + api.register { + name = "rules", + scope = "project", + kind = "list:string", + } + api.register { name = "startproject", scope = "solution", @@ -631,6 +656,18 @@ tokens = true, } + api.register { + name = "strictaliasing", + scope = "config", + kind = "string", + allowed = { + "Off", + "Level1", + "Level2", + "Level3", + } + } + api.register { name = "system", scope = "config", @@ -764,7 +801,7 @@ -- 09 Apr 2013 - api.deprecateField("buildrule", DOC_URL .. "Custom_Build_Commands", + api.deprecateField("buildrule", nil, function(value) if value.description then buildmessage(value.description) @@ -773,16 +810,18 @@ buildoutputs(value.outputs) end) + -- 17 Jun 2013 - api.deprecateValue("flags", "Component", DOC_URL .. "buildaction", + api.deprecateValue("flags", "Component", nil, function(value) buildaction "Component" end) + -- 26 Sep 2013 - api.deprecateValue("flags", { "EnableSSE", "EnableSSE2" }, DOC_URL .. "vectorextensions", + api.deprecateValue("flags", { "EnableSSE", "EnableSSE2" }, nil, function(value) vectorextensions(value:sub(7)) end, @@ -790,7 +829,8 @@ vectorextension "Default" end) - api.deprecateValue("flags", { "FloatFast", "FloatStrict" }, DOC_URL .. "floatingpoint", + + api.deprecateValue("flags", { "FloatFast", "FloatStrict" }, nil, function(value) floatingpoint(value:sub(6)) end, @@ -798,7 +838,8 @@ floatingpoint "Default" end) - api.deprecateValue("flags", { "NativeWChar", "NoNativeWChar" }, DOC_URL .. "nativewchar", + + api.deprecateValue("flags", { "NativeWChar", "NoNativeWChar" }, nil, function(value) local map = { NativeWChar = "On", NoNativeWChar = "Off" } nativewchar(map[value] or "Default") @@ -807,7 +848,8 @@ nativewchar "Default" end) - api.deprecateValue("flags", { "Optimize", "OptimizeSize", "OptimizeSpeed" }, DOC_URL .. "optimize", + + api.deprecateValue("flags", { "Optimize", "OptimizeSize", "OptimizeSpeed" }, nil, function(value) local map = { Optimize = "On", OptimizeSize = "Size", OptimizeSpeed = "Speed" } optimize (map[value] or "Off") @@ -816,7 +858,8 @@ optimize "Off" end) - api.deprecateValue("flags", { "Optimise", "OptimiseSize", "OptimiseSpeed" }, DOC_URL .. "optimize", + + api.deprecateValue("flags", { "Optimise", "OptimiseSize", "OptimiseSpeed" }, nil, function(value) local map = { Optimise = "On", OptimiseSize = "Size", OptimiseSpeed = "Speed" } optimize (map[value] or "Off") @@ -825,7 +868,8 @@ optimize "Off" end) - api.deprecateValue("flags", { "ExtraWarnings", "NoWarnings" }, DOC_URL .. "warnings", + + api.deprecateValue("flags", { "ExtraWarnings", "NoWarnings" }, nil, function(value) local map = { ExtraWarnings = "Extra", NoWarnings = "Off" } warnings (map[value] or "Default") @@ -835,6 +879,36 @@ end) + -- 10 Nov 2014 + + api.deprecateValue("flags", "Managed", nil, + function(value) + clr "On" + end, + function(value) + clr "Off" + end) + + + api.deprecateValue("flags", "NoEditAndContinue", nil, + function(value) + editAndContinue "Off" + end, + function(value) + editAndContinue "On" + end) + + + api.deprecateValue("flags", "Unsafe", nil, + function(value) + clr "Unsafe" + end, + function(value) + clr "On" + end) + + + ----------------------------------------------------------------------------- -- -- Install Premake's default set of command line arguments. @@ -934,6 +1008,9 @@ -- ----------------------------------------------------------------------------- + clr "Off" + editAndContinue "On" + -- Setting a default language makes some validation easier later language "C++" diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 7ad01e5c..ee42991c 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -401,7 +401,7 @@ function make.ldFlags(cfg, toolset) - local flags = table.join(toolset.getLibraryDirectories(cfg), toolset.getldflags(cfg)) + local flags = table.join(toolset.getLibraryDirectories(cfg), toolset.getldflags(cfg), cfg.linkoptions) _p(' ALL_LDFLAGS += $(LDFLAGS)%s', make.list(flags)) end diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index dcfd66fc..4706f37d 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -222,7 +222,7 @@ _p(2,'prompt') _p(2,'4') - if cfg.flags.Unsafe then + if cfg.clr == "Unsafe" then _p(2,'true') end diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index fd056e63..6eede15d 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -749,9 +749,9 @@ return 1 else -- Edit-and-continue doesn't work for some configurations - if cfg.flags.NoEditAndContinue or + if not cfg.editAndContinue or config.isOptimizedBuild(cfg) or - cfg.flags.Managed or + cfg.clr ~= p.OFF or cfg.system == "x64" then return 3 @@ -856,7 +856,7 @@ function m.additionalLinkerOptions(cfg, toolset) local flags if toolset then - flags = toolset.getldflags(cfg) + flags = table.join(toolset.getldflags(cfg), cfg.linkoptions) else flags = cfg.linkoptions end @@ -922,7 +922,7 @@ local cfg, filecfg = config.normalize(cfg) if not filecfg and not config.isOptimizedBuild(cfg) - and not cfg.flags.Managed + and cfg.clr == p.OFF and not cfg.flags.NoRuntimeChecks then p.w('BasicRuntimeChecks="3"') @@ -1062,7 +1062,7 @@ function m.detect64BitPortabilityProblems(cfg) local prjcfg, filecfg = config.normalize(cfg) - if _ACTION < "vs2008" and not cfg.flags.Managed and cfg.warnings ~= "Off" and not filecfg then + if _ACTION < "vs2008" and cfg.clr == p.OFF and cfg.warnings ~= p.OFF and not filecfg then p.w('Detect64BitPortabilityProblems="%s"', tostring(not cfg.flags.No64BitChecks)) end end @@ -1164,7 +1164,7 @@ local windows, managed, makefile for cfg in project.eachconfig(prj) do if cfg.system == p.WINDOWS then windows = true end - if cfg.flags.Managed then managed = true end + if cfg.clr ~= p.OFF then managed = true end if vstudio.isMakefile(cfg) then makefile = true end end @@ -1261,7 +1261,7 @@ function m.managedExtensions(cfg) - if cfg.flags.Managed then + if cfg.clr ~= p.OFF then p.w('ManagedExtensions="1"') end end @@ -1272,7 +1272,7 @@ if config.isDebugBuild(cfg) and cfg.debugformat ~= "c7" and not cfg.flags.NoMinimalRebuild and - not cfg.flags.Managed and + cfg.clr == p.OFF and not cfg.flags.MultiProcessorCompile then p.w('MinimalRebuild="true"') @@ -1500,7 +1500,7 @@ function m.runtimeTypeInfo(cfg) - if cfg.flags.NoRTTI and not cfg.flags.Managed then + if cfg.flags.NoRTTI and cfg.clr == p.OFF then p.w('RuntimeTypeInfo="false"') end end @@ -1607,7 +1607,7 @@ function m.warnAsError(cfg) - if cfg.flags.FatalCompileWarnings and cfg.warnings ~= "Off" then + if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then p.w('WarnAsError="true"') end end @@ -1618,7 +1618,7 @@ local prjcfg, filecfg = config.normalize(cfg) local level - if cfg.warnings == "Off" then + if cfg.warnings == p.OFF then level = "0" elseif cfg.warnings == "Extra" then level = "4" diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 393eea0c..0164a981 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -241,7 +241,7 @@ m.elements.itemDefinitionGroup = function(cfg) if cfg.kind == p.UTILITY then return { - m.customRuleVars, + m.ruleVars, m.buildEvents, } else @@ -253,7 +253,7 @@ m.buildEvents, m.imageXex, m.deploy, - m.customRuleVars, + m.ruleVars, } end end @@ -491,23 +491,19 @@ -- Write out project-level custom rule variables. --- - function m.customRuleVars(cfg) - local vars = p.api.getCustomVars() - table.foreachi(cfg.project._customRules, function(rule) + function m.ruleVars(cfg) + for i = 1, #cfg.rules do + local rule = p.global.getRule(cfg.rules[i]) + local contents = p.capture(function () p.push() - for _, var in ipairs(vars) do - if cfg[var] then - local key = p.api.getCustomVarKey(var) - local value = cfg[var] - - if type(value) == "table" then - local fmt = p.api.getCustomListFormat(var) - value = table.concat(value, fmt[1]) - end - - if value and #value > 0 then - m.element(key, nil, '%s', value) + for prop in p.rule.eachProperty(rule) do + local fld = p.rule.getPropertyField(rule, prop) + local value = cfg[fld.name] + if value ~= nil then + value = p.rule.getPropertyString(rule, prop, value) + if value ~= nil and #value > 0 then + m.element(prop.name, nil, '%s', value) end end end @@ -515,11 +511,11 @@ end) if #contents > 0 then - p.push('<%s>', rule) + p.push('<%s>', rule.name) p.outln(contents) - p.pop('', rule) + p.pop('', rule.name) end - end) + end end @@ -559,12 +555,12 @@ --- m.elements.fileGroups = { - "ClInclude", - "ClCompile", - "None", - "ResourceCompile", - "CustomBuild", - "CustomRule" + "clInclude", + "clCompile", + "none", + "resourceCompile", + "customBuild", + "customRule" } m.elements.files = function(prj, groups) @@ -583,7 +579,7 @@ end - function m.ClCompileFiles(prj, group) + function m.clCompileFiles(prj, group) local files = group.ClCompile or {} if #files > 0 then p.push('') @@ -622,7 +618,7 @@ end - function m.ClIncludeFiles(prj, groups) + function m.clIncludeFiles(prj, groups) local files = groups.ClInclude or {} if #files > 0 then p.push('') @@ -634,7 +630,7 @@ end - function m.CustomBuildFiles(prj, groups) + function m.customBuildFiles(prj, groups) local files = groups.CustomBuild or {} if #files > 0 then p.push('') @@ -672,48 +668,42 @@ end - function m.CustomRuleFiles(prj, groups) - local vars = p.api.getCustomVars() - - -- Look for rules that aren't in the built-in rule list - for rule, files in pairs(groups) do - if not table.contains(m.elements.fileGroups, rule) and #files > 0 then + function m.customRuleFiles(prj, groups) + for i = 1, #prj.rules do + local rule = p.global.getRule(prj.rules[i]) + local files = groups[rule.name] + if files and #files > 0 then p.push('') - for _, file in ipairs(files) do - -- Capture any rule variables that have been set + for _, file in ipairs(files) do local contents = p.capture(function() p.push() - for _, var in ipairs(vars) do + for prop in p.rule.eachProperty(rule) do + local fld = p.rule.getPropertyField(rule, prop) + for cfg in project.eachconfig(prj) do - local condition = m.condition(cfg) local fcfg = fileconfig.getconfig(file, cfg) - if fcfg and fcfg[var] then - local key = p.api.getCustomVarKey(var) - local value = fcfg[var] - - if type(value) == "table" then - local fmt = p.api.getCustomListFormat(var) - value = table.concat(value, fmt[1]) - end - + if fcfg and fcfg[fld.name] then + local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name]) if value and #value > 0 then - m.element(key, condition, '%s', value) + m.element(prop.name, m.condition(cfg), '%s', value) end end end + end p.pop() end) if #contents > 0 then - p.push('<%s Include=\"%s\">', rule, path.translate(file.relpath)) + p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath)) p.outln(contents) - p.pop('', rule) + p.pop('', rule.name) else - p.x('<%s Include=\"%s\" />', rule, path.translate(file.relpath)) + p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) end end + p.pop('') end end @@ -721,7 +711,7 @@ - function m.NoneFiles(prj, groups) + function m.noneFiles(prj, groups) local files = groups.None or {} if #files > 0 then p.push('') @@ -733,7 +723,7 @@ end - function m.ResourceCompileFiles(prj, groups) + function m.resourceCompileFiles(prj, groups) local files = groups.ResourceCompile or {} if #files > 0 then p.push('') @@ -764,17 +754,21 @@ function m.categorize(prj, file) - -- If any configuration for this file uses a custom build step or a - -- custom, externally defined rule, that's the category to use + -- If any configuration for this file uses a custom build step, + -- that's the category to use for cfg in project.eachconfig(prj) do local fcfg = fileconfig.getconfig(file, cfg) if fileconfig.hasCustomBuildRule(fcfg) then return "CustomBuild" - elseif fcfg and fcfg._customRule then - return fcfg._customRule end end + -- If there is a custom rule associated with it, use that + local rule = p.global.getRuleForFile(file.name, prj.rules) + if rule then + return rule.name + end + -- Otherwise use the file extension to deduce a category if path.iscppfile(file.name) then return "ClCompile" @@ -823,7 +817,7 @@ -- m.elements.projectReferences = function(prj, ref) - if prj.flags.Managed then + if prj.clr ~= p.OFF then return { m.referenceProject, m.referencePrivate, @@ -957,8 +951,14 @@ function m.clrSupport(cfg) - if cfg.flags.Managed then - _p(2,'true') + local value + if cfg.clr == "On" or cfg.clr == "Unsafe" then + value = "true" + elseif cfg.clr ~= p.OFF then + value = cfg.clr + end + if value then + p.w('%s', value) end end @@ -998,9 +998,9 @@ if cfg.debugformat == "c7" then value = "OldStyle" elseif cfg.architecture == "x64" or - cfg.flags.Managed or + cfg.clr ~= p.OFF or config.isOptimizedBuild(cfg) or - cfg.flags.NoEditAndContinue + not cfg.editAndContinue then value = "ProgramDatabase" else @@ -1045,7 +1045,7 @@ function m.entryPointSymbol(cfg) if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and not cfg.flags.WinMain and - not cfg.flags.Managed and + cfg.clr == p.OFF and cfg.system ~= premake.XBOX360 then _p(3,'mainCRTStartup') @@ -1155,11 +1155,13 @@ function m.importExtensionTargets(prj) p.w('') p.push('') - table.foreachi(prj.customRules, function(value) - value = path.translate(project.getrelative(prj, value)) - value = path.appendExtension(value, ".targets") - p.x('', value) - end) + + for i = 1, #prj.rules do + local rule = p.global.getRule(prj.rules[i]) + local loc = project.getrelative(prj, premake.filename(rule, ".targets")) + p.x('', path.translate(loc)) + end + p.pop('') end @@ -1174,11 +1176,13 @@ function m.importExtensionSettings(prj) p.w('') p.push('') - table.foreachi(prj.customRules, function(value) - value = path.translate(project.getrelative(prj, value)) - value = path.appendExtension(value, ".props") - p.x('', value) - end) + + for i = 1, #prj.rules do + local rule = p.global.getRule(prj.rules[i]) + local loc = project.getrelative(prj, premake.filename(rule, ".props")) + p.x('', path.translate(loc)) + end + p.pop('') end @@ -1212,7 +1216,7 @@ if cfg.system == premake.WINDOWS then isWin = true end - if cfg.flags.Managed then + if cfg.clr ~= p.OFF then isManaged = true end if vstudio.isMakefile(cfg) then @@ -1486,7 +1490,7 @@ function m.runtimeTypeInfo(cfg) - if cfg.flags.NoRTTI and not cfg.flags.Managed then + if cfg.flags.NoRTTI and cfg.clr == p.OFF then _p(3,'false') end end @@ -1546,7 +1550,7 @@ function m.treatWarningAsError(cfg) - if cfg.flags.FatalCompileWarnings and cfg.warnings ~= "Off" then + if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then p.w('true') end end diff --git a/src/base/api.lua b/src/base/api.lua index a6a627fd..d7eb0ba1 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -46,7 +46,17 @@ end _G[containerName] = function(name) - return api._setContainer(class, name) + local c = api._setContainer(class, name) + if api._isIncludingExternal then + c.external = true + end + return c + end + + _G["external" .. containerName:capitalized()] = function(name) + local c = _G[containerName](name) + c.external = true + return c end return class @@ -54,6 +64,20 @@ +--- +-- Register a general-purpose includeExternal() call which works just like +-- include(), but marks any containers created while evaluating the included +-- scripts as external. +--- + + function includeExternal(fname) + api._isIncludingExternal = true + include(fname) + api._isIncludingExternal = nil + end + + + --- -- Return the global configuration container. You could just call global() -- too, but this is much faster. @@ -238,7 +262,7 @@ -- create a setter function for it _G[name] = function(value) - return api.callback(field, value) + return api.storeField(field, value) end if premake.field.removes(field) then @@ -460,15 +484,15 @@ -- gets parceled out to the individual set...() functions. -- - function api.callback(field, value) - if not value then + function api.storeField(field, value) + if value == nil then return end if field.deprecated and type(field.deprecated.handler) == "function" then field.deprecated.handler(value) - if api._deprecations ~= "off" then - premake.warnOnce(field.name, "the field %s has been deprecated.\n %s", field.name, field.deprecated.message or "") + if field.deprecated.message and api._deprecations ~= "off" then + premake.warnOnce(field.name, "the field %s has been deprecated.\n %s", field.name, field.deprecated.message) if api._deprecations == "error" then error("deprecation errors enabled", 3) end end end @@ -486,6 +510,7 @@ end + -- -- The remover: adds values to be removed to the "removes" field on -- current configuration. Removes are keyed by the associated field, @@ -496,7 +521,7 @@ function api.remove(field, value) -- right now, ignore calls with no value; later might want to -- return the current baked value - if not value then return end + if value == nil then return end local target = api.target(field) if not target then @@ -517,9 +542,9 @@ if field.deprecated[value] then local handler = field.deprecated[value] if handler.remove then handler.remove(value) end - if api._deprecations ~= "off" then + if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, value, handler.message or "") + premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, value, handler.message) if api._deprecations == "error" then error { msg="deprecation errors enabled" } end @@ -618,9 +643,9 @@ if field.deprecated and field.deprecated[canonical] then local handler = field.deprecated[canonical] handler.add(canonical) - if api._deprecations ~= "off" then + if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, canonical, handler.message or "") + premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, canonical, handler.message) if api._deprecations == "error" then return nil, "deprecation errors enabled" end @@ -639,18 +664,9 @@ --- function api.reset() - -- Clear out all top level objects + -- Clear out all top level objects, but keep the root config + api.scope.global.rules = {} api.scope.global.solutions = {} - - -- Remove all custom variables - local vars = api.getCustomVars() - for i, var in ipairs(vars) do - local f = premake.field.get(var) - api.unregister(f) - end - - -- Remove all custom list variable formats - api._customVarFormats = {} end @@ -687,6 +703,47 @@ +--- +-- Boolean field kind; converts common yes/no strings into true/false values. +--- + + premake.field.kind("boolean", { + store = function(field, current, value, processor) + local mapping = { + ["false"] = false, + ["no"] = false, + ["off"] = false, + ["on"] = true, + ["true"] = true, + ["yes"] = true, + } + + if type(value) == "string" then + value = mapping[value:lower()] + if value == nil then + error { msg="expected boolean; got " .. value } + end + return value + end + + if type(value) == "boolean" then + return value + end + + if type(value) == "number" then + return (value ~= 0) + end + + return (value ~= nil) + end, + compare = function(field, a, b, processor) + return (a == b) + end + }) + + + + -- -- Directory data kind; performs wildcard directory searches, converts -- results to absolute paths. @@ -1044,26 +1101,6 @@ --- --- Activates a reference to an external, non-Premake generated project. --- --- @param name --- The name of the project. If a project with this name already --- exists, it is made current, otherwise a new project is created --- with this name. If no name is provided, the most recently defined --- project is made active. --- @return --- The active project object. --- - - function external(name) - local prj = project(name) - prj.external = true; - return prj - end - - - -- -- Define a new action. -- @@ -1086,125 +1123,3 @@ function newoption(opt) premake.option.add(opt) end - - ------------------------------------------------------------------------------ --- --- The custom*() functions act as wrappers that define new ad-hoc fields --- on the fly, to support arbitrary custom rule variables. These should be --- considered experimental and temporary for now as a more complete rule- --- generating solution will certainly be needed, but I will do my best to --- deprecate them cleanly when that time comes. --- ------------------------------------------------------------------------------ - - api._customVarFormats = {} - - function api.getCustomVars() - local vars = {} - for f in premake.field.each() do - if f.name:startswith("_custom_") then - table.insert(vars, f.name) - end - end - return vars - end - - - function api.getCustomVarKey(var) - return var:sub(9) - end - - - function api.getCustomListFormat(var) - local key = api.getCustomVarKey(var) - return api._customVarFormats[key] or { " " } - end - - - function api.setCustomVar(name, kind, value) - local fieldName = "_custom_" .. name - local field = premake.field.get(fieldName) - if not field then - field = premake.field.new { - name = fieldName, - scope = "config", - kind = kind, - tokens = true, - } - end - api.callback(field, value) - end - - - function customVar(value) - if type(value) ~= "table" or #value ~= 2 then - error("invalid value for customVar()") - end - api.setCustomVar(value[1], "string", value[2]) - end - - - function customList(value) - if type(value) ~= "table" or #value < 2 then - error("invalid value for customList()") - end - - local name = value[1] - table.remove(value, 1) - api.setCustomVar(name, "list:string", value) - end - - - function customListFormat(value) - if type(value) ~= "table" or #value < 2 then - error("invalid value for customListFormat()") - end - - local name = value[1] - table.remove(value, 1) - api._customVarFormats[name] = value - end - - - function customRule(value) - -- Store the rule name in the current configuration, like a - -- normal set-field operation would - local fieldName = "_customRule" - local field = premake.field.get(fieldName) - if not field then - field = premake.field.new { - name = fieldName, - scope = "config", - kind = "string", - } - end - api.callback(field, value) - - -- Wild hack: I need a way to get all of the custom rule names that are - -- in use within a project. The rule names are currently only associated - -- with individual files. Rather than iterating over all the files after - -- the fact, keep a master list of rule names in the first configuration - -- block of the project. This way it will come out of the baking system - -- looking like a normal list:string field. - fieldName = "_customRules" - field = premake.field.get(fieldName) - if not field then - field = premake.field.new { - name = fieldName, - scope = "config", - kind = "list:string" - } - end - - local cset = api.target(field) - if not cset then - local err = string.format("unable to set rule in %s scope, should be project", api.scope.current.class.name) - error(err, 2) - end - - local current = cset.current - cset.current = cset.blocks[1] - api.callback(field, value) - cset.current = current - end diff --git a/src/base/config.lua b/src/base/config.lua index 9583a1ed..d5f55af9 100755 --- a/src/base/config.lua +++ b/src/base/config.lua @@ -4,9 +4,12 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- - premake.config = {} - local project = premake.project - local config = premake.config + local p = premake + + p.config = {} + + local project = p.project + local config = p.config --- @@ -91,8 +94,8 @@ -- Can't link managed and unmanaged projects - local cfgManaged = project.isdotnet(cfg.project) or (cfg.flags.Managed ~= nil) - local tgtManaged = project.isdotnet(target.project) or (target.flags.Managed ~= nil) + local cfgManaged = project.isdotnet(cfg.project) or (cfg.clr ~= p.OFF) + local tgtManaged = project.isdotnet(target.project) or (target.clr ~= p.OFF) return (cfgManaged == tgtManaged) end @@ -111,7 +114,7 @@ -- Unmanaged projects can never link managed assemblies - if isManaged and not cfg.flags.Managed then + if isManaged and cfg.clr == p.OFF then return false end @@ -438,7 +441,7 @@ -- function config.isOptimizedBuild(cfg) - return cfg.optimize ~= nil and cfg.optimize ~= "Off" and cfg.optimize ~= "Debug" + return cfg.optimize ~= nil and cfg.optimize ~= p.OFF and cfg.optimize ~= "Debug" end diff --git a/src/base/configset.lua b/src/base/configset.lua index 33766f52..f50404ff 100644 --- a/src/base/configset.lua +++ b/src/base/configset.lua @@ -89,12 +89,12 @@ -- If the filter contains a file path, make it relative to -- this block's basedir - if value and abspath and not cset.compiled and block._basedir ~= basedir then + if value ~= nil and abspath and not cset.compiled and block._basedir ~= basedir then basedir = block._basedir filter.files = path.getrelative(basedir, abspath) end - if value and (cset.compiled or criteria.matches(block._criteria, filter)) then + if value ~= nil and (cset.compiled or criteria.matches(block._criteria, filter)) then -- If value is an object, return a copy of it so that any -- changes later made to it by the caller won't alter the -- original value (that was a tough bug to find) diff --git a/src/base/container.lua b/src/base/container.lua index 4850eccb..55be14cc 100644 --- a/src/base/container.lua +++ b/src/base/container.lua @@ -70,8 +70,10 @@ self.class = class self.name = name + self.filename = name self.script = _SCRIPT self.basedir = os.getcwd() + self.external = false for childClass in container.eachChildClass(class) do self[childClass.pluralName] = {} diff --git a/src/base/detoken.lua b/src/base/detoken.lua index bd0749aa..1f6f17c6 100644 --- a/src/base/detoken.lua +++ b/src/base/detoken.lua @@ -79,6 +79,10 @@ end function expandvalue(value) + if type(value) ~= "string" then + return + end + local count repeat value, count = value:gsub("%%{(.-)}", function(token) diff --git a/src/base/field.lua b/src/base/field.lua index 5ba28840..2c4303ab 100644 --- a/src/base/field.lua +++ b/src/base/field.lua @@ -290,7 +290,7 @@ local kinds = string.explode(f._kind, ":", true) for i, kind in ipairs(kinds) do local value = field._kinds[kind][tag] - if value then + if value ~= nil then return value end end diff --git a/src/base/global.lua b/src/base/global.lua index 04086653..f142608f 100644 --- a/src/base/global.lua +++ b/src/base/global.lua @@ -47,6 +47,48 @@ +--- +-- Retrieve a rule by name or index. +-- +-- @param key +-- The rule key, either a string name or integer index. +-- @returns +-- The rule with the provided key. +--- + + function global.getRule(key) + local root = p.api.rootContainer() + return root.rules[key] + end + + + +--- +-- Retrieve the rule to applies to the provided file name, if any such +-- rule exists. +-- +-- @param fname +-- The name of the file. +-- @param rules +-- A list of rule names to be included in the search. If not specified, +-- all rules will be checked. +-- @returns +-- The rule, is one has been registered, or nil. +--- + + function global.getRuleForFile(fname, rules) + local ext = path.getextension(fname):lower() + for rule in global.eachRule() do + if not rules or table.contains(rules, rule.name) then + if rule.fileExtension == ext then + return rule + end + end + end + end + + + --- -- Retrieve a solution by name or index. -- @@ -58,7 +100,5 @@ function global.getSolution(key) local root = p.api.rootContainer() - if root.solutions then - return root.solutions[key] - end + return root.solutions[key] end diff --git a/src/base/oven.lua b/src/base/oven.lua index 53da552e..ae5eda40 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -94,7 +94,6 @@ -- to project configurations. self.configs = oven.bakeConfigs(self) - end @@ -194,6 +193,14 @@ + function p.rule.bake(r) + table.sort(r.propertyDefinition, function (a, b) + return a.name < b.name + end) + end + + + -- -- Assigns a unique objects directory to every configuration of every project -- in the solution, taking any objdir settings into account, to ensure builds diff --git a/src/base/premake.lua b/src/base/premake.lua index f31196b0..be71e6a4 100644 --- a/src/base/premake.lua +++ b/src/base/premake.lua @@ -4,10 +4,12 @@ -- Copyright (c) 2002-2014 Jason Perkins and the Premake project -- - local solution = premake.solution - local project = premake.project - local config = premake.config - local field = premake.field + local p = premake + + local solution = p.solution + local project = p.project + local config = p.config + local field = p.field @@ -180,7 +182,7 @@ --- function premake.filename(obj, ext) - local fname = obj.location + local fname = obj.location or obj.basedir if ext and not ext:startswith(".") then fname = path.join(fname, ext) else @@ -189,7 +191,7 @@ function premake.filename(obj, ext) fname = fname .. ext end end - return fname + return path.getabsolute(fname) end @@ -367,6 +369,14 @@ end premake.error("project '%s' does not have a language", prj.name) end + -- all rules must exist + for i = 1, #prj.rules do + local rule = prj.rules[i] + if not p.global.getRule(rule) then + premake.error("project '%s' uses missing rule '%s'", prj.name, rule) + end + end + -- check for out of scope fields premake.validateScopes(prj, "project", ctx) end diff --git a/src/base/project.lua b/src/base/project.lua index a5dd802f..cb996641 100755 --- a/src/base/project.lua +++ b/src/base/project.lua @@ -12,6 +12,15 @@ +--- +-- Alias the old external() call to the new externalProject(), to distinguish +-- between it and externalRule(). +--- + + external = externalProject + + + --- -- Create a new project container instance. --- @@ -19,7 +28,6 @@ function project.new(name) local prj = p.container.new(project, name) prj.uuid = os.uuid(name) - prj.filename = name if p.api.scope.group then prj.group = p.api.scope.group.name diff --git a/src/base/rule.lua b/src/base/rule.lua new file mode 100644 index 00000000..d17228ad --- /dev/null +++ b/src/base/rule.lua @@ -0,0 +1,161 @@ +--- +-- base/rule.lua +-- Defines rule sets for generated custom rule files. +-- Copyright (c) 2014 Jason Perkins and the Premake project +--- + + local p = premake + p.rule = p.api.container("rule", p.global) + + local rule = p.rule + + + +--- +-- Create a new rule container instance. +--- + + function rule.new(name) + local self = p.container.new(rule, name) + + -- create a variable setting function. Do a version with lowercased + -- first letter(s) to match Premake's naming style for other calls + + _G[name .. "Vars"] = function(vars) + rule.setVars(self, vars) + end + + local lowerName = name:gsub("^%u+", string.lower) + _G[lowerName .. "Vars"] = _G[name .. "Vars"] + + return self + end + + + +--- +-- Enumerate the property definitions for a rule. +--- + + function rule.eachProperty(self) + local props = self.propertyDefinition + local i = 0 + return function () + i = i + 1 + if i <= #props then + return props[i] + end + end + end + + + +--- +-- Find a property definition by its name. +-- +-- @param name +-- The property name. +-- @returns +-- The property definition if found, nil otherwise. +--- + + function rule.getProperty(self, name) + local props = self.propertyDefinition + for i = 1, #props do + local prop = props[i] + if prop.name == name then + return prop + end + end + end + + + +--- +-- Find the field definition for one this rule's properties. This field +-- can then be used with the api.* functions to manipulate the property's +-- values in the current configuration scope. +-- +-- @param prop +-- The property definition. +-- @return +-- The field definition for the property; this will be created if it +-- does not already exist. +--- + + function rule.getPropertyField(self, prop) + if prop._field then + return prop._field + end + + local kind = prop.kind or "string" + if kind == "list" then + kind = "list:string" + end + + local fld = p.field.new { + name = "_rule_" .. self.name .. "_" .. prop.name, + scope = "config", + kind = kind, + tokens = true, + } + + prop._field = fld + return fld + end + + + +--- +-- Given the value for a particular property, returns a formatted string. +-- +-- @param prop +-- The property definition. +-- @param value +-- The value of the property to be formatted. +-- @returns +-- A string value. +--- + + function rule.getPropertyString(self, prop, value) + -- list? + if type(value) == "table" then + local sep = prop.separator or " " + return table.concat(value, sep) + end + + -- enum? + if prop.values then + local i = table.indexof(prop.values, value) + return tostring(i) + end + + -- primitive + value = tostring(value) + if #value > 0 then + return value + else + return nil + end + end + + + +--- +-- Set one or more rule variables in the current configuration scope. +-- +-- @param vars +-- A key-value list of variables to set and their corresponding values. +--- + + function rule.setVars(self, vars) + for key, value in pairs(vars) do + local prop = rule.getProperty(self, key) + if not prop then + error (string.format("rule '%s' does not have property '%s'", self.name, key)) + end + + local fld = rule.getPropertyField(self, prop) + p.api.storeField(fld, value) + end + end diff --git a/src/base/rules.lua b/src/base/rules.lua deleted file mode 100644 index 731350d7..00000000 --- a/src/base/rules.lua +++ /dev/null @@ -1,20 +0,0 @@ ---- --- base/rules.lua --- Defines rule sets for generated custom rule files. --- Copyright (c) 2014 Jason Perkins and the Premake project ---- - - local p = premake - p.rule = p.api.container("rule", p.global) - - local rule = p.rule - - - ---- --- Create a new rule container instance. ---- - - function rule.new(name) - return p.container.new(rule, name) - end diff --git a/src/base/solution.lua b/src/base/solution.lua index 13f0357d..e008d968 100644 --- a/src/base/solution.lua +++ b/src/base/solution.lua @@ -18,7 +18,6 @@ function solution.new(name) local sln = p.container.new(solution, name) - sln.filename = name return sln end diff --git a/src/base/string.lua b/src/base/string.lua index 2a85ee47..3c28f521 100644 --- a/src/base/string.lua +++ b/src/base/string.lua @@ -5,6 +5,16 @@ -- +-- +-- Capitalize the first letter of the string. +-- + + function string.capitalized(self) + return self:gsub("^%l", string.upper) + end + + + -- -- Returns true if the string has a match for the plain specified pattern -- diff --git a/src/base/table.lua b/src/base/table.lua index 81285309..e01e7a87 100644 --- a/src/base/table.lua +++ b/src/base/table.lua @@ -168,15 +168,15 @@ -- function table.indexof(tbl, obj) - local count = #tbl - for i = 1, count do - if tbl[i] == obj then - return i + for k, v in pairs(tbl) do + if v == obj then + return k end end end + --- -- Insert a new value into a table in the position after the specified -- existing value. If the specified value does not exist in the table, diff --git a/src/host/lua_auxlib.c b/src/host/lua_auxlib.c index f2807713..27883a3e 100644 --- a/src/host/lua_auxlib.c +++ b/src/host/lua_auxlib.c @@ -49,7 +49,7 @@ LUALIB_API int luaL_loadfile (lua_State* L, const char* filename) const char* script_dir; lua_getglobal(L, "_SCRIPT_DIR"); script_dir = lua_tostring(L, -1); - if (script_dir[0] == '$') { + if (script_dir && script_dir[0] == '$') { /* call path.getabsolute() to handle ".." if present */ lua_pushcfunction(L, path_getabsolute); lua_pushstring(L, filename); @@ -75,7 +75,7 @@ LUALIB_API int luaL_loadfile (lua_State* L, const char* filename) if (z == OKAY) { lua_pushcclosure(L, chunk_wrapper, 2); } - else { + else if (z == LUA_YIELD) { lua_pushstring(L, "cannot open "); lua_pushstring(L, filename); lua_pushstring(L, ": No such file or directory"); diff --git a/src/host/premake.c b/src/host/premake.c index 51f7f32b..ecba9fa7 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -332,11 +332,5 @@ int premake_load_embedded_script(lua_State* L, const char* filename) lua_concat(L, 2); /* Load the chunk */ - i = luaL_loadbuffer(L, chunk, strlen(chunk), filename); - if (i != OKAY) { - lua_pop(L, 1); - printf("Failed to load embedded script '%s': %s\n", filename, lua_tostring(L, -1)); - } - - return i; + return luaL_loadbuffer(L, chunk, strlen(chunk), filename); } diff --git a/src/tools/clang.lua b/src/tools/clang.lua index 3ecae3a5..5a8df4ee 100644 --- a/src/tools/clang.lua +++ b/src/tools/clang.lua @@ -166,7 +166,6 @@ function clang.getldflags(cfg) local flags = config.mapFlags(cfg, clang.ldflags) - flags = table.join(flags, cfg.linkoptions) return flags end diff --git a/src/tools/dotnet.lua b/src/tools/dotnet.lua index ed59f058..8ad8c61e 100644 --- a/src/tools/dotnet.lua +++ b/src/tools/dotnet.lua @@ -200,10 +200,12 @@ -- dotnet.flags = { + clr = { + Unsafe = "/unsafe", + }, flags = { FatalWarning = "/warnaserror", Symbols = "/debug", - Unsafe = "/unsafe" }, optimize = { On = "/optimize", diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index 00c63ddd..41eb74e0 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -40,7 +40,9 @@ flags = { FatalCompileWarnings = "-Werror", NoFramePointer = "-fomit-frame-pointer", - Symbols = "-g" + ShadowedVariables = "-Wshadow", + Symbols = "-g", + UndefinedIdentifiers = "-Wundef", }, floatingpoint = { Fast = "-ffast-math", @@ -51,6 +53,12 @@ if cfg.system ~= premake.WINDOWS then return "-fPIC" end end, }, + strictaliasing = { + Off = "-fno-strict-aliasing", + Level1 = { "-fstrict-aliasing", "-Wstrict-aliasing=1" }, + Level2 = { "-fstrict-aliasing", "-Wstrict-aliasing=2" }, + Level3 = { "-fstrict-aliasing", "-Wstrict-aliasing=3" }, + }, optimize = { Off = "-O0", On = "-O2", @@ -177,7 +185,6 @@ function gcc.getldflags(cfg) local flags = config.mapFlags(cfg, gcc.ldflags) - flags = table.join(flags, cfg.linkoptions) return flags end diff --git a/src/tools/msc.lua b/src/tools/msc.lua index 13a64c3a..1d1426d3 100644 --- a/src/tools/msc.lua +++ b/src/tools/msc.lua @@ -25,6 +25,12 @@ -- msc.cflags = { + clr = { + On = "/clr", + Unsafe = "/clr", + Pure = "/clr:pure", + Safe = "/clr:safe", + }, flags = { FatalCompileWarnings = "/WX", MultiProcessorCompile = "/MP", @@ -168,7 +174,6 @@ function msc.getldflags(cfg) local map = iif(cfg.kind ~= premake.STATICLIB, msc.linkerFlags, msc.librarianFlags) local flags = config.mapFlags(cfg, map) - flags = table.join(flags, cfg.linkoptions) table.insert(flags, 1, "/NOLOGO") return flags end diff --git a/tests/_tests.lua b/tests/_tests.lua index e438fef2..37a30172 100644 --- a/tests/_tests.lua +++ b/tests/_tests.lua @@ -37,6 +37,7 @@ return { "oven/test_objdirs.lua", -- API tests + "api/test_boolean_kind.lua", "api/test_containers.lua", "api/test_directory_kind.lua", "api/test_list_kind.lua", @@ -114,6 +115,7 @@ return { "actions/vstudio/vc2010/test_project_refs.lua", "actions/vstudio/vc2010/test_prop_sheet.lua", "actions/vstudio/vc2010/test_resource_compile.lua", + "actions/vstudio/vc2010/test_rule_vars.lua", -- Visual Studio 2012 "actions/vs2012/test_csproj_common_props.lua", diff --git a/tests/actions/make/cs/test_flags.lua b/tests/actions/make/cs/test_flags.lua index caeadf2f..3c63247f 100644 --- a/tests/actions/make/cs/test_flags.lua +++ b/tests/actions/make/cs/test_flags.lua @@ -43,7 +43,7 @@ -- function suite.onUnsafe() - flags { "Unsafe" } + clr "Unsafe" prepare() test.capture [[ FLAGS = /unsafe /noconfig diff --git a/tests/actions/vstudio/cs2005/test_compiler_props.lua b/tests/actions/vstudio/cs2005/test_compiler_props.lua index eb303592..43929e4d 100644 --- a/tests/actions/vstudio/cs2005/test_compiler_props.lua +++ b/tests/actions/vstudio/cs2005/test_compiler_props.lua @@ -44,7 +44,7 @@ -- function suite.allowUnsafeBlocks_onUnsafeFlag() - flags { "Unsafe" } + clr "Unsafe" prepare() test.capture [[ diff --git a/tests/actions/vstudio/sln2005/test_projects.lua b/tests/actions/vstudio/sln2005/test_projects.lua index 3d713712..144cfbc9 100755 --- a/tests/actions/vstudio/sln2005/test_projects.lua +++ b/tests/actions/vstudio/sln2005/test_projects.lua @@ -184,7 +184,7 @@ EndProject -- function suite.translatesEnvironmentVars() - external "MyProject" + externalProject "MyProject" location "$(SDK_LOCATION)/MyProject" uuid "30A1B994-C2C6-485F-911B-FB4674366DA8" kind "SharedLib" diff --git a/tests/actions/vstudio/vc200x/test_assembly_refs.lua b/tests/actions/vstudio/vc200x/test_assembly_refs.lua index 69c12267..b8157b1f 100644 --- a/tests/actions/vstudio/vc200x/test_assembly_refs.lua +++ b/tests/actions/vstudio/vc200x/test_assembly_refs.lua @@ -16,7 +16,7 @@ function suite.setup() sln = test.createsolution() - flags { "Managed" } + clr "On" end local function prepare(platform) diff --git a/tests/actions/vstudio/vc200x/test_compiler_block.lua b/tests/actions/vstudio/vc200x/test_compiler_block.lua index b6c1ed47..9a0c86a3 100644 --- a/tests/actions/vstudio/vc200x/test_compiler_block.lua +++ b/tests/actions/vstudio/vc200x/test_compiler_block.lua @@ -364,7 +364,7 @@ -- Verify the correct Detect64BitPortabilityProblems settings are used when _ACTION < "VS2008". -- - function suite.runtimeLibraryIsDebug_onVS2005() + function suite._64BitPortabilityOn_onVS2005() _ACTION = "vs2005" prepare() test.capture [[ @@ -382,6 +382,23 @@ ]] end + function suite._64BitPortabilityOff_onVS2005_andCLR() + _ACTION = "vs2005" + clr "On" + prepare() + test.capture [[ + + ]] + end + -- -- Verify the correct warnings settings are used when no warnings are enabled. diff --git a/tests/actions/vstudio/vc200x/test_project.lua b/tests/actions/vstudio/vc200x/test_project.lua index 830cc094..56608ee8 100644 --- a/tests/actions/vstudio/vc200x/test_project.lua +++ b/tests/actions/vstudio/vc200x/test_project.lua @@ -76,7 +76,7 @@ -- function suite.keywordIsCorrect_onManagedC() - flags { "Managed" } + clr "On" prepare() test.capture [[ @@ -606,7 +607,8 @@ -- function suite.debugFormat_onManagedCode() - flags { "Symbols", "Managed" } + flags "Symbols" + clr "On" prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_config_props.lua b/tests/actions/vstudio/vc2010/test_config_props.lua index d9eb5072..d202cbc6 100755 --- a/tests/actions/vstudio/vc2010/test_config_props.lua +++ b/tests/actions/vstudio/vc2010/test_config_props.lua @@ -110,12 +110,13 @@ ]] end + -- -- Check the support for Managed C++. -- - function suite.clrSupport_onManaged() - flags "Managed" + function suite.clrSupport_onClrOn() + clr "On" prepare() test.capture [[ @@ -125,6 +126,50 @@ ]] end + function suite.clrSupport_onClrOff() + clr "Off" + prepare() + test.capture [[ + + Application + false + ]] + end + + function suite.clrSupport_onClrUnsafe() + clr "Unsafe" + prepare() + test.capture [[ + + Application + false + true + ]] + end + + function suite.clrSupport_onClrSafe() + clr "Safe" + prepare() + test.capture [[ + + Application + false + Safe + ]] + end + + function suite.clrSupport_onClrPure() + clr "Pure" + prepare() + test.capture [[ + + Application + false + Pure + ]] + end + + -- -- Check the support for building with MFC. -- diff --git a/tests/actions/vstudio/vc2010/test_extension_settings.lua b/tests/actions/vstudio/vc2010/test_extension_settings.lua index 78de7363..5f4dbadc 100644 --- a/tests/actions/vstudio/vc2010/test_extension_settings.lua +++ b/tests/actions/vstudio/vc2010/test_extension_settings.lua @@ -16,6 +16,8 @@ local sln function suite.setup() + rule "MyRules" + rule "MyOtherRules" sln = test.createsolution() end @@ -45,8 +47,7 @@ -- function suite.addsImport_onEachRulesFile() - customRules "MyRules" - customRules "MyOtherRules" + rules { "MyRules", "MyOtherRules" } prepare() test.capture [[ @@ -63,13 +64,13 @@ -- function suite.usesProjectRelativePaths() - customRules "path/to/MyRules" + rules "MyRules" location "build" prepare() test.capture [[ - + ]] end diff --git a/tests/actions/vstudio/vc2010/test_extension_targets.lua b/tests/actions/vstudio/vc2010/test_extension_targets.lua index 4b957075..77ed8d19 100644 --- a/tests/actions/vstudio/vc2010/test_extension_targets.lua +++ b/tests/actions/vstudio/vc2010/test_extension_targets.lua @@ -16,6 +16,8 @@ local sln function suite.setup() + rule "MyRules" + rule "MyOtherRules" sln = test.createsolution() end @@ -45,8 +47,7 @@ -- function suite.addsImport_onEachRulesFile() - customRules "MyRules" - customRules "MyOtherRules" + rules { "MyRules", "MyOtherRules" } prepare() test.capture [[ @@ -63,13 +64,13 @@ -- function suite.usesProjectRelativePaths() - customRules "path/to/MyRules" + rules { "MyRules" } location "build" prepare() test.capture [[ - + ]] end diff --git a/tests/actions/vstudio/vc2010/test_files.lua b/tests/actions/vstudio/vc2010/test_files.lua index ab95b583..9f6c2d36 100755 --- a/tests/actions/vstudio/vc2010/test_files.lua +++ b/tests/actions/vstudio/vc2010/test_files.lua @@ -16,6 +16,15 @@ function suite.setup() _ACTION = "vs2010" + + rule "Animation" + fileExtension ".dae" + propertyDefinition { + name = "AdditionalOptions", + kind = "list", + separator = ";" + } + sln = test.createsolution() end @@ -522,12 +531,11 @@ -- Check handling of files using custom rule definitions. -- - function suite.correctlyCategorized_onCustomRule() + function suite.isCategorizedByRule() + rules "Animation" files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" prepare() - test.capture [[ + test.capture [[ @@ -535,107 +543,20 @@ end - function suite.customRule_onLiteralVars() + function suite.listsPerConfigRuleVars() + rules "Animation" files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" - customVar { "GenerateDebugInfo", "True" } + filter { "files:hello.*", "configurations:Debug" } + animationVars { AdditionalOptions = { "File1", "File2" }} + filter { "files:hello.*", "configurations:Release" } + animationVars { AdditionalOptions = { "File3" }} prepare() test.capture [[ - True - True + File1;File2 + File3 ]] end - - - function suite.customRule_onLiteralPath() - targetdir "../bin/%{cfg.buildcfg}" - files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" - customVar { "OutputDirectory", "%{cfg.targetdir}/anim" } - prepare() - test.capture [[ - - - ../bin/Debug/anim - ../bin/Release/anim - - - ]] - end - - - function suite.customRule_onPerConfigLiteralVars() - files { "hello.dae" } - filter { "files:**.dae" } - customRule "Animation" - filter { "files:**.dae", "configurations:Debug" } - customVar { "GenerateDebugInfo", "True" } - prepare() - test.capture [[ - - - True - - - ]] - end - - - function suite.customRule_onListVars() - files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" - customList { "ExtraDependencies", "File1", "File2" } - prepare() - test.capture [[ - - - File1 File2 - File1 File2 - - - ]] - end - - - function suite.customRule_onPerConfigListVars() - files { "hello.dae" } - filter { "files:**.dae" } - customRule "Animation" - customList { "ExtraDependencies", "File1", "File2" } - filter { "files:**.dae", "configurations:Release" } - customList { "ExtraDependencies", "File3" } - prepare() - test.capture [[ - - - File1 File2 - File1 File2 File3 - - - ]] - end - - - function suite.customRule_onListVarsWithCustomFormat() - files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" - customListFormat { "ExtraDependencies", ";" } - customList { "ExtraDependencies", "File1", "File2" } - prepare() - test.capture [[ - - - File1;File2 - File1;File2 - - - ]] - end \ No newline at end of file diff --git a/tests/actions/vstudio/vc2010/test_filters.lua b/tests/actions/vstudio/vc2010/test_filters.lua index c0b0fd36..d699e695 100644 --- a/tests/actions/vstudio/vc2010/test_filters.lua +++ b/tests/actions/vstudio/vc2010/test_filters.lua @@ -171,9 +171,12 @@ -- function suite.filter_onCustomRule() + rules "Animation" files { "hello.dae" } - filter "files:**.dae" - customRule "Animation" + + rule "Animation" + fileExtension ".dae" + prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_globals.lua b/tests/actions/vstudio/vc2010/test_globals.lua index 20e7728e..0d0f08a4 100755 --- a/tests/actions/vstudio/vc2010/test_globals.lua +++ b/tests/actions/vstudio/vc2010/test_globals.lua @@ -46,7 +46,7 @@ -- function suite.keywordIsCorrect_onManagedC() - flags { "Managed" } + clr "On" prepare() test.capture [[ @@ -64,7 +64,7 @@ -- function suite.frameworkVersionIsCorrect_onManagedC() - flags { "Managed" } + clr "On" framework "4.5" prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_project_refs.lua b/tests/actions/vstudio/vc2010/test_project_refs.lua index 39e195e7..236ca463 100644 --- a/tests/actions/vstudio/vc2010/test_project_refs.lua +++ b/tests/actions/vstudio/vc2010/test_project_refs.lua @@ -82,7 +82,7 @@ function suite.referencesAreRelative_onDifferentProjectLocation() links { "MyProject" } - flags { "Managed" } + clr "On" prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_rule_vars.lua b/tests/actions/vstudio/vc2010/test_rule_vars.lua new file mode 100644 index 00000000..21735223 --- /dev/null +++ b/tests/actions/vstudio/vc2010/test_rule_vars.lua @@ -0,0 +1,108 @@ +-- +-- tests/actions/vstudio/vc2010/test_rule_vars.lua +-- Validate generation of custom rule variables at the project level. +-- Copyright (c) 2014 Jason Perkins and the Premake project +-- + + local suite = test.declare("vstudio_vs2010_rule_vars") + + local vc2010 = premake.vstudio.vc2010 + + + +-- +-- Setup +-- + + local sln, prj + + function suite.setup() + rule "MyRule" + sln, prj = test.createsolution() + rules { "MyRule" } + end + + local function createVar(def) + rule "MyRule" + propertyDefinition(def) + project "MyProject" + end + + local function prepare() + local cfg = test.getconfig(prj, "Debug") + vc2010.ruleVars(cfg) + end + + +-- +-- If the configuration has a rule, but does not set any variables, +-- nothing should be written. +-- + + function suite.noOutput_onNoVars() + prepare() + test.isemptycapture() + end + + +-- +-- Test setting the various property kinds. +-- + + function suite.onStringVar() + createVar { name="MyVar", kind="string" } + myRuleVars { MyVar = "hello" } + prepare() + test.capture [[ + + hello + + ]] + end + + + function suite.onBooleanVar() + createVar { name="MyVar", kind="boolean" } + myRuleVars { MyVar = false } + prepare() + test.capture [[ + + false + + ]] + end + + + function suite.onListVar() + createVar { name="MyVar", kind="list" } + myRuleVars { MyVar = { "a", "b", "c" } } + prepare() + test.capture [[ + + a b c + + ]] + end + + + function suite.onEnumVar() + createVar { + name = "MyVar", + values = { + [0] = "Win32", + [1] = "Win64", + }, + switch = { + [0] = "-m32", + [1] = "-m64", + }, + value = 0, + } + myRuleVars { MyVar = "Win32" } + prepare() + test.capture [[ + + 0 + + ]] + end diff --git a/tests/api/test_boolean_kind.lua b/tests/api/test_boolean_kind.lua new file mode 100644 index 00000000..4d99105e --- /dev/null +++ b/tests/api/test_boolean_kind.lua @@ -0,0 +1,79 @@ +-- +-- tests/api/test_boolean_kind.lua +-- Tests the boolean API value type. +-- Copyright (c) 2014 Jason Perkins and the Premake project +-- + + local suite = test.declare("api_boolean_kind") + local api = premake.api + + +-- +-- Setup and teardown +-- + + function suite.setup() + api.register { + name = "testapi", + kind = "boolean", + scope = "project", + } + test.createsolution() + end + + function suite.teardown() + testapi = nil + end + + + +-- +-- Check setting of true values. +-- + + function suite.setsTrue_onYes() + testapi "yes" + test.istrue(api.scope.project.testapi) + end + + function suite.setsTrue_onBooleanTrue() + testapi (true) + test.istrue(api.scope.project.testapi) + end + + function suite.setsTrue_onNonZero() + testapi (1) + test.istrue(api.scope.project.testapi) + end + + +-- +-- Check setting of false values. +-- + + function suite.setsFalse_onNo() + testapi "no" + test.isfalse(api.scope.project.testapi) + end + + function suite.setsFalse_onBooleanFalse() + testapi (false) + test.isfalse(api.scope.project.testapi) + end + + function suite.setsFalse_onZero() + testapi (0) + test.isfalse(api.scope.project.testapi) + end + + +-- +-- Raise an error on an invalid string value. +-- + + function suite.raisesError_onDisallowedValue() + ok, err = pcall(function () + testapi "maybe" + end) + test.isfalse(ok) + end diff --git a/tests/base/test_configset.lua b/tests/base/test_configset.lua index 0983de75..223ee2c1 100644 --- a/tests/base/test_configset.lua +++ b/tests/base/test_configset.lua @@ -175,16 +175,16 @@ function suite.remove_onExactValueMatch() local f = field.get("flags") - configset.store(cset, f, { "Symbols", "Unsafe", "NoRTTI" }) - configset.remove(cset, f, { "Unsafe" }) + configset.store(cset, f, { "Symbols", "WinMain", "NoRTTI" }) + configset.remove(cset, f, { "WinMain" }) test.isequal({ "Symbols", "NoRTTI" }, configset.fetch(cset, f, {})) end function suite.remove_onMultipleValues() local f = field.get("flags") - configset.store(cset, f, { "Symbols", "NoExceptions", "Unsafe", "NoRTTI" }) + configset.store(cset, f, { "Symbols", "NoExceptions", "WinMain", "NoRTTI" }) configset.remove(cset, f, { "NoExceptions", "NoRTTI" }) - test.isequal({ "Symbols", "Unsafe" }, configset.fetch(cset, f, {})) + test.isequal({ "Symbols", "WinMain" }, configset.fetch(cset, f, {})) end diff --git a/tests/base/test_validation.lua b/tests/base/test_validation.lua index 9b076eb4..c0668096 100644 --- a/tests/base/test_validation.lua +++ b/tests/base/test_validation.lua @@ -130,3 +130,17 @@ premake.validate() test.stderr("'configurations' on config") end + + +-- +-- If a rule is specified for inclusion, it must have been defined. +-- + + function suite.fails_onNoSuchRule() + solution "MySolution" + configurations { "Debug", "Release" } + project "MyProject" + rules { "NoSuchRule" } + test.isfalse(pcall(premake.validate)) + end + diff --git a/tests/config/test_links.lua b/tests/config/test_links.lua index 659b0fd4..dc894d68 100755 --- a/tests/config/test_links.lua +++ b/tests/config/test_links.lua @@ -111,7 +111,7 @@ function suite.skipsAssemblies_onManagedCpp() system "windows" - flags { "Managed" } + clr "On" links { "user32", "System.dll" } local r = prepare("all", "fullpath") test.isequal({ "user32.lib" }, r) @@ -125,7 +125,7 @@ function suite.skipsUnmanagedLibs_onManagedLinkage() system "windows" - flags { "Managed" } + clr "On" links { "user32", "System.dll" } local r = prepare("all", "fullpath", "managed") test.isequal({ "System.dll" }, r) @@ -161,20 +161,20 @@ end function suite.canLink_ManagedCppAndManagedCpp() - flags { "Managed" } + clr "On" links { "MyProject2" } project "MyProject2" kind "StaticLib" language "C++" - flags { "Managed" } + clr "On" local r = prepare("all", "fullpath") test.isequal({ "MyProject2.lib" }, r) end function suite.canLink_ManagedCppAndCs() - flags { "Managed" } + clr "On" links { "MyProject2" } project "MyProject2" diff --git a/tests/tools/test_gcc.lua b/tests/tools/test_gcc.lua index ec2e78af..57c0d06d 100644 --- a/tests/tools/test_gcc.lua +++ b/tests/tools/test_gcc.lua @@ -402,3 +402,32 @@ test.isequal({ '-I"$(IntDir)/includes"' }, gcc.getincludedirs(cfg, cfg.includedirs)) end + + +-- +-- Check handling of strict aliasing flags. +-- + + function suite.cflags_onNoStrictAliasing() + strictaliasing "Off" + prepare() + test.contains("-fno-strict-aliasing", gcc.getcflags(cfg)) + end + + function suite.cflags_onLevel1Aliasing() + strictaliasing "Level1" + prepare() + test.contains({ "-fstrict-aliasing", "-Wstrict-aliasing=1" }, gcc.getcflags(cfg)) + end + + function suite.cflags_onLevel2Aliasing() + strictaliasing "Level2" + prepare() + test.contains({ "-fstrict-aliasing", "-Wstrict-aliasing=2" }, gcc.getcflags(cfg)) + end + + function suite.cflags_onLevel3Aliasing() + strictaliasing "Level3" + prepare() + test.contains({ "-fstrict-aliasing", "-Wstrict-aliasing=3" }, gcc.getcflags(cfg)) + end diff --git a/tests/tools/test_msc.lua b/tests/tools/test_msc.lua index ffcc2348..7f09c697 100644 --- a/tests/tools/test_msc.lua +++ b/tests/tools/test_msc.lua @@ -235,3 +235,33 @@ prepare() test.contains("/DLL", msc.getldflags(cfg)) end + + + +-- +-- Check handling of CLR settings. +-- + + function suite.cflags_onClrOn() + clr "On" + prepare() + test.contains("/clr", msc.getcflags(cfg)) + end + + function suite.cflags_onClrUnsafe() + clr "Unsafe" + prepare() + test.contains("/clr", msc.getcflags(cfg)) + end + + function suite.cflags_onClrSafe() + clr "Safe" + prepare() + test.contains("/clr:safe", msc.getcflags(cfg)) + end + + function suite.cflags_onClrPure() + clr "Pure" + prepare() + test.contains("/clr:pure", msc.getcflags(cfg)) + end