Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
Copyright (c) 2013-2015 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.

View File

@@ -0,0 +1,9 @@
# Premake Extension to support Android NDK projects
Supported features:
* VisualStudio support through [vs-android](https://code.google.com/p/vs-android/)
Todo:
* gmake support

View File

@@ -0,0 +1,8 @@
return {
"_preload.lua",
"android.lua",
"vsandroid_vcxproj.lua",
"vsandroid_sln2005.lua",
"vsandroid_vstudio.lua",
"vsandroid_androidproj.lua",
}

View File

@@ -0,0 +1,104 @@
--
-- Name: android/_preload.lua
-- Purpose: Define the Android API's.
-- Author: Manu Evans
-- Copyright: (c) 2013-2015 Manu Evans and the Premake project
--
local p = premake
local api = p.api
--
-- Register the Android extension
--
api.addAllowed("system", p.ANDROID)
api.addAllowed("architecture", { "armv5", "armv7", "aarch64", "mips", "mips64", "arm" })
api.addAllowed("vectorextensions", { "NEON", "MXU" })
api.addAllowed("exceptionhandling", {"UnwindTables"})
api.addAllowed("flags", { "Thumb" })
api.addAllowed("kind", p.PACKAGING)
premake.action._list["vs2015"].valid_kinds = table.join(premake.action._list["vs2015"].valid_kinds, { p.PACKAGING })
premake.action._list["vs2017"].valid_kinds = table.join(premake.action._list["vs2017"].valid_kinds, { p.PACKAGING })
premake.action._list["vs2019"].valid_kinds = table.join(premake.action._list["vs2019"].valid_kinds, { p.PACKAGING })
local osoption = p.option.get("os")
if osoption ~= nil then
table.insert(osoption.allowed, { "android", "Android" })
end
-- add system tags for android.
os.systemTags[p.ANDROID] = { "android", "mobile" }
--
-- Register Android properties
--
api.register {
name = "floatabi",
scope = "config",
kind = "string",
allowed = {
"soft",
"softfp",
"hard",
},
}
api.register {
name = "androidapilevel",
scope = "config",
kind = "integer",
}
api.register {
name = "toolchainversion",
scope = "config",
kind = "string",
allowed = {
"4.6", -- NDK GCC versions
"4.8",
"4.9",
"3.4", -- NDK clang versions
"3.5",
"3.6",
"3.8",
"5.0",
},
}
api.register {
name = "stl",
scope = "config",
kind = "string",
allowed = {
"none",
"gabi++",
"stlport",
"gnu",
"libc++",
},
}
api.register {
name = "thumbmode",
scope = "config",
kind = "string",
allowed = {
"thumb",
"arm",
"disabled",
},
}
api.register {
name = "androidapplibname",
scope = "config",
kind = "string"
}
return function(cfg)
return (cfg.system == p.ANDROID)
end

View File

@@ -0,0 +1,25 @@
--
-- Create an android namespace to isolate the additions
--
local p = premake
if not p.modules.android then
require ("vstudio")
p.modules.android = {}
if _ACTION < "vs2015" then
configuration { "Android" }
system "android"
toolset "gcc"
end
-- TODO: configure Android debug environment...
include("vsandroid_vcxproj.lua")
include("vsandroid_sln2005.lua")
include("vsandroid_vstudio.lua")
include("vsandroid_androidproj.lua")
end
return p.modules.android

View File

@@ -0,0 +1,6 @@
require ("android")
return {
"test_android_files.lua",
"test_android_project.lua",
}

View File

@@ -0,0 +1,47 @@
local p = premake
local suite = test.declare("test_android_files")
local vc2010 = p.vstudio.vc2010
--
-- Setup
--
local wks, prj
function suite.setup()
p.action.set("vs2015")
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
system "android"
vc2010.files(prj)
end
--
-- Test filtering of source files into the correct categories.
--
function suite.none_onJavaFile()
files { "hello.java" }
prepare()
test.capture [[
<ItemGroup>
<None Include="hello.java" />
</ItemGroup>
]]
end
function suite.javaCompile_onJavaFile()
kind "Packaging"
files { "hello.java" }
prepare()
test.capture [[
<ItemGroup>
<JavaCompile Include="hello.java" />
</ItemGroup>
]]
end

View File

@@ -0,0 +1,150 @@
local p = premake
local suite = test.declare("test_android_project")
local vc2010 = p.vstudio.vc2010
local android = p.modules.android
--
-- Setup
--
local wks, prj
function suite.setup()
p.action.set("vs2015")
system "android"
wks, prj = test.createWorkspace()
end
local function prepare()
local cfg = test.getconfig(prj, "Debug")
vc2010.clCompile(cfg)
end
local function prepareGlobals()
prj = test.getproject(wks, 1)
vc2010.globals(prj)
end
function suite.minVisualStudioVersion_14()
prepareGlobals()
test.capture [[
<PropertyGroup Label="Globals">
<ProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ProjectGuid>
<Keyword>Android</Keyword>
<RootNamespace>MyProject</RootNamespace>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<ApplicationType>Android</ApplicationType>
<ApplicationTypeRevision>2.0</ApplicationTypeRevision>]]
end
function suite.minVisualStudioVersion_15()
p.action.set("vs2017")
prepareGlobals()
test.capture [[
<PropertyGroup Label="Globals">
<ProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ProjectGuid>
<LatestTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</LatestTargetPlatformVersion>
<Keyword>Android</Keyword>
<RootNamespace>MyProject</RootNamespace>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<ApplicationType>Android</ApplicationType>
<ApplicationTypeRevision>3.0</ApplicationTypeRevision>]]
end
function suite.minVisualStudioVersion_16()
p.action.set("vs2019")
prepareGlobals()
test.capture [[
<PropertyGroup Label="Globals">
<ProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ProjectGuid>
<Keyword>Android</Keyword>
<RootNamespace>MyProject</RootNamespace>
<MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>
<ApplicationType>Android</ApplicationType>
<ApplicationTypeRevision>3.0</ApplicationTypeRevision>]]
end
function suite.noOptions()
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
</ClCompile>]]
end
function suite.rttiOff()
rtti "Off"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
</ClCompile>]]
end
function suite.rttiOn()
rtti "On"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
]]
end
function suite.exceptionHandlingOff()
exceptionhandling "Off"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
</ClCompile>]]
end
function suite.exceptionHandlingOn()
exceptionhandling "On"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<ExceptionHandling>Enabled</ExceptionHandling>
]]
end
function suite.cppdialect_cpp11()
cppdialect "C++11"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<CppLanguageStandard>c++11</CppLanguageStandard>
]]
end
function suite.cppdialect_cpp14()
cppdialect "C++14"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<CppLanguageStandard>c++1y</CppLanguageStandard>
]]
end
function suite.cppdialect_cpp17()
cppdialect "C++17"
prepare()
test.capture [[
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<CppLanguageStandard>c++1z</CppLanguageStandard>
]]
end

View File

@@ -0,0 +1,271 @@
--
-- android/vsandroid_androidproj.lua
-- vs-android integration for vstudio.
-- Copyright (c) 2012-2015 Manu Evans and the Premake project
--
local p = premake
local android = p.modules.android
local vsandroid = p.modules.vsandroid
local vc2010 = p.vstudio.vc2010
local vstudio = p.vstudio
local project = p.project
--
-- Add android tools to vstudio actions.
--
premake.override(vstudio.vs2010, "generateProject", function(oldfn, prj)
if prj.kind == p.PACKAGING then
p.eol("\r\n")
p.indent(" ")
p.escaper(vstudio.vs2010.esc)
if project.iscpp(prj) then
p.generate(prj, ".androidproj", vc2010.generate)
-- Skip generation of empty user files
local user = p.capture(function() vc2010.generateUser(prj) end)
if #user > 0 then
p.generate(prj, ".androidproj.user", function() p.outln(user) end)
end
end
else
oldfn(prj)
end
end)
premake.override(vstudio, "projectfile", function(oldfn, prj)
if prj.kind == p.PACKAGING then
return premake.filename(prj, ".androidproj")
else
return oldfn(prj)
end
end)
premake.override(vstudio, "tool", function(oldfn, prj)
if prj.kind == p.PACKAGING then
return "39E2626F-3545-4960-A6E8-258AD8476CE5"
else
return oldfn(prj)
end
end)
premake.override(vc2010.elements, "globals", function (oldfn, cfg)
local elements = oldfn(cfg)
if cfg.kind == premake.PACKAGING then
-- Remove "IgnoreWarnCompileDuplicatedFilename".
local pos = table.indexof(elements, vc2010.ignoreWarnDuplicateFilename)
table.remove(elements, pos)
elements = table.join(elements, {
android.projectVersion
})
end
return elements
end)
function android.projectVersion(cfg)
_p(2, "<RootNamespace>%s</RootNamespace>", cfg.project.name)
_p(2, "<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>")
_p(2, "<ProjectVersion>1.0</ProjectVersion>")
end
premake.override(vc2010.elements, "configurationProperties", function(oldfn, cfg)
local elements = oldfn(cfg)
if cfg.kind == p.PACKAGING then
elements = {
android.androidAPILevel,
vc2010.useDebugLibraries,
}
end
return elements
end)
premake.override(vc2010.elements, "itemDefinitionGroup", function(oldfn, cfg)
local elements = oldfn(cfg)
if cfg.kind == p.PACKAGING then
elements = {
android.antPackage,
}
end
return elements
end)
premake.override(vc2010, "importDefaultProps", function(oldfn, prj)
if prj.kind == p.PACKAGING then
p.w('<Import Project="$(AndroidTargetsPath)\\Android.Default.props" />')
else
oldfn(prj)
end
end)
premake.override(vc2010, "importLanguageSettings", function(oldfn, prj)
if prj.kind == p.PACKAGING then
p.w('<Import Project="$(AndroidTargetsPath)\\Android.props" />')
else
oldfn(prj)
end
end)
premake.override(vc2010, "propertySheets", function(oldfn, cfg)
if cfg.kind ~= p.PACKAGING then
oldfn(cfg)
end
end)
premake.override(vc2010.elements, "outputProperties", function(oldfn, cfg)
if cfg.kind == p.PACKAGING then
return {
android.outDir,
vc2010.intDir,
vc2010.targetName,
}
else
return oldfn(cfg)
end
end)
function android.outDir(cfg)
vc2010.element("OutDir", nil, "%s\\", cfg.buildtarget.directory)
end
premake.override(vc2010, "importLanguageTargets", function(oldfn, prj)
if prj.kind == p.PACKAGING then
p.w('<Import Project="$(AndroidTargetsPath)\\Android.targets" />')
else
oldfn(prj)
end
end)
function android.link(cfg, file)
-- default the seperator to '/' as that is what is searched for
-- below. Otherwise the function will use target seperator which
-- could be '\\' and result in failure to create links.
local fname = path.translate(file.relpath, '/')
-- Files that live outside of the project tree need to be "linked"
-- and provided with a project relative pseudo-path. Check for any
-- leading "../" sequences and, if found, remove them and mark this
-- path as external.
local link, count = fname:gsub("%.%.%/", "")
local external = (count > 0) or fname:find(':', 1, true) or (file.vpath and file.vpath ~= file.relpath)
-- Try to provide a little bit of flexibility by allowing virtual
-- paths for external files. Would be great to support them for all
-- files but Visual Studio chokes if file is already in project area.
if external and file.vpath ~= file.relpath then
link = file.vpath
end
if external then
vc2010.element("Link", nil, path.translate(link))
end
end
vc2010.categories.AndroidManifest = {
name = "AndroidManifest",
priority = 99,
emitFiles = function(prj, group)
vc2010.emitFiles(prj, group, "AndroidManifest", {vc2010.generatedFile, android.link, android.manifestSubType})
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "AndroidManifest")
end
}
function android.manifestSubType(cfg, file)
vc2010.element("SubType", nil, "Designer")
end
vc2010.categories.AntBuildXml = {
name = "AntBuildXml",
priority = 99,
emitFiles = function(prj, group)
vc2010.emitFiles(prj, group, "AntBuildXml", {vc2010.generatedFile, android.link})
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "AntBuildXml")
end
}
vc2010.categories.AntProjectPropertiesFile = {
name = "AntProjectPropertiesFile",
priority = 99,
emitFiles = function(prj, group)
vc2010.emitFiles(prj, group, "AntProjectPropertiesFile", {vc2010.generatedFile, android.link})
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "AntProjectPropertiesFile")
end
}
vc2010.categories.JavaCompile = {
name = "JavaCompile",
priority = 99,
emitFiles = function(prj, group)
vc2010.emitFiles(prj, group, "JavaCompile", {vc2010.generatedFile, android.link})
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "JavaCompile")
end
}
vc2010.categories.Content = {
name = "Content",
priority = 99,
emitFiles = function(prj, group)
vc2010.emitFiles(prj, group, "Content", {vc2010.generatedFile, android.link})
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "Content")
end
}
premake.override(vc2010, "categorizeFile", function(base, prj, file)
if prj.kind ~= p.PACKAGING then
return base(prj, file)
end
local filename = path.getname(file.name):lower()
local extension = path.getextension(filename)
if filename == "androidmanifest.xml" then
return vc2010.categories.AndroidManifest
elseif filename == "build.xml" then
return vc2010.categories.AntBuildXml
elseif filename == "project.properties" then
return vc2010.categories.AntProjectPropertiesFile
elseif extension == ".java" then
return vc2010.categories.JavaCompile
else
return vc2010.categories.Content
end
end)

View File

@@ -0,0 +1,36 @@
--
-- android/vsandroid_sln2005.lua
-- vs-android integration for vstudio.
-- Copyright (c) 2012-2015 Manu Evans and the Premake project
--
local p = premake
local android = p.modules.android
local vsandroid = p.modules.vsandroid
local sln2005 = p.vstudio.sln2005
--
-- Add android tools to vstudio actions.
--
premake.override(sln2005.elements, "projectConfigurationPlatforms", function(oldfn, cfg, context)
local elements = oldfn(cfg, context)
if cfg.system == premake.ANDROID and _ACTION >= "vs2015" then
elements = table.join(elements, {
android.deployProject
})
end
return elements
end)
function android.deployProject(cfg, context)
if context.prjCfg.kind == p.PACKAGING and _ACTION >= "vs2015" then
p.w('{%s}.%s.Deploy.0 = %s|%s', context.prj.uuid, context.descriptor, context.platform, context.architecture)
end
end

View File

@@ -0,0 +1,642 @@
--
-- android/vsandroid_vcxproj.lua
-- vs-android integration for vstudio.
-- Copyright (c) 2012-2015 Manu Evans and the Premake project
--
local p = premake
p.modules.vsandroid = { }
local android = p.modules.android
local vsandroid = p.modules.vsandroid
local vc2010 = p.vstudio.vc2010
local vstudio = p.vstudio
local project = p.project
local config = p.config
--
-- Utility functions
--
local function setBoolOption(optionName, flag, value)
if flag ~= nil then
vc2010.element(optionName, nil, value)
end
end
--
-- Add android tools to vstudio actions.
--
if vstudio.vs2010_architectures ~= nil then
if _ACTION >= "vs2015" then
vstudio.vs2010_architectures.arm = "ARM"
else
vstudio.vs2010_architectures.android = "Android"
end
end
--
-- Extend global properties
--
premake.override(vc2010.elements, "globals", function (oldfn, prj)
local elements = oldfn(prj)
if prj.system == premake.ANDROID and prj.kind ~= premake.PACKAGING then
-- Remove "IgnoreWarnCompileDuplicatedFilename".
local pos = table.indexof(elements, vc2010.ignoreWarnDuplicateFilename)
table.remove(elements, pos)
elements = table.join(elements, {
android.androidApplicationType
})
end
return elements
end)
premake.override(vc2010.elements, "globalsCondition", function (oldfn, prj, cfg)
local elements = oldfn(prj, cfg)
if cfg.system == premake.ANDROID and cfg.system ~= prj.system and cfg.kind ~= premake.PACKAGING then
elements = table.join(elements, {
android.androidApplicationType
})
end
return elements
end)
function android.androidApplicationType(cfg)
vc2010.element("Keyword", nil, "Android")
vc2010.element("RootNamespace", nil, "%s", cfg.project.name)
if _ACTION >= "vs2019" then
vc2010.element("MinimumVisualStudioVersion", nil, "16.0")
elseif _ACTION >= "vs2017" then
vc2010.element("MinimumVisualStudioVersion", nil, "15.0")
elseif _ACTION >= "vs2015" then
vc2010.element("MinimumVisualStudioVersion", nil, "14.0")
end
vc2010.element("ApplicationType", nil, "Android")
if _ACTION >= "vs2017" then
vc2010.element("ApplicationTypeRevision", nil, "3.0")
elseif _ACTION >= "vs2015" then
vc2010.element("ApplicationTypeRevision", nil, "2.0")
else
vc2010.element("ApplicationTypeRevision", nil, "1.0")
end
end
--
-- Extend configurationProperties.
--
premake.override(vc2010.elements, "configurationProperties", function(oldfn, cfg)
local elements = oldfn(cfg)
if cfg.kind ~= p.UTILITY and cfg.kind ~= p.PACKAGING and cfg.system == premake.ANDROID then
table.remove(elements, table.indexof(elements, vc2010.characterSet))
table.remove(elements, table.indexof(elements, vc2010.wholeProgramOptimization))
table.remove(elements, table.indexof(elements, vc2010.windowsSDKDesktopARMSupport))
elements = table.join(elements, {
android.androidAPILevel,
android.androidStlType,
})
if _ACTION >= "vs2015" then
elements = table.join(elements, {
android.thumbMode,
})
end
end
return elements
end)
function android.androidAPILevel(cfg)
if cfg.androidapilevel ~= nil then
vc2010.element("AndroidAPILevel", nil, "android-" .. cfg.androidapilevel)
end
end
function android.androidStlType(cfg)
if cfg.stl ~= nil then
local stlType = {
["none"] = "system",
["gabi++"] = "gabi++",
["stlport"] = "stlport",
["gnu"] = "gnustl",
["libc++"] = "c++",
}
local postfix = iif(cfg.staticruntime == "On", "_static", "_shared")
local runtimeLib = iif(cfg.stl == "none", "system", stlType[cfg.stl] .. postfix)
if _ACTION >= "vs2015" then
vc2010.element("UseOfStl", nil, runtimeLib)
else
vc2010.element("AndroidStlType", nil, runtimeLib)
end
end
end
function android.thumbMode(cfg)
if cfg.thumbmode ~= nil then
local thumbMode =
{
thumb = "Thumb",
arm = "ARM",
disabled = "Disabled",
}
vc2010.element("ThumbMode", nil, thumbMode[cfg.thumbmode])
end
end
-- Note: this function is already patched in by vs2012...
premake.override(vc2010, "platformToolset", function(oldfn, cfg)
if cfg.system ~= premake.ANDROID then
return oldfn(cfg)
end
if _ACTION >= "vs2015" then
local gcc_map = {
["4.6"] = "GCC_4_6",
["4.8"] = "GCC_4_8",
["4.9"] = "GCC_4_9",
}
local clang_map = {
["3.4"] = "Clang_3_4",
["3.5"] = "Clang_3_5",
["3.6"] = "Clang_3_6",
["3.8"] = "Clang_3_8",
["5.0"] = "Clang_5_0",
}
if cfg.toolchainversion ~= nil then
local map = iif(cfg.toolset == "gcc", gcc_map, clang_map)
local ts = map[cfg.toolchainversion]
if ts == nil then
p.error('Invalid toolchainversion for the selected toolset (%s).', cfg.toolset or "clang")
end
vc2010.element("PlatformToolset", nil, ts)
end
else
local archMap = {
arm = "armv5te", -- should arm5 be default? vs-android thinks so...
arm5 = "armv5te",
arm7 = "armv7-a",
mips = "mips",
x86 = "x86",
}
local arch = cfg.architecture or "arm"
if (cfg.architecture ~= nil or cfg.toolchainversion ~= nil) and archMap[arch] ~= nil then
local defaultToolsetMap = {
arm = "arm-linux-androideabi-",
armv5 = "arm-linux-androideabi-",
armv7 = "arm-linux-androideabi-",
aarch64 = "aarch64-linux-android-",
mips = "mipsel-linux-android-",
mips64 = "mips64el-linux-android-",
x86 = "x86-",
x86_64 = "x86_64-",
}
local toolset = defaultToolsetMap[arch]
if cfg.toolset == "clang" then
error("The clang toolset is not yet supported by vs-android", 2)
toolset = toolset .. "clang"
elseif cfg.toolset and cfg.toolset ~= "gcc" then
error("Toolset not supported by the android NDK: " .. cfg.toolset, 2)
end
local version = cfg.toolchainversion or iif(cfg.toolset == "clang", "3.5", "4.9")
vc2010.element("PlatformToolset", nil, toolset .. version)
vc2010.element("AndroidArch", nil, archMap[arch])
end
end
end)
--
-- Extend clCompile.
--
premake.override(vc2010.elements, "clCompile", function(oldfn, cfg)
local elements = oldfn(cfg)
if cfg.system == premake.ANDROID then
elements = table.join(elements, {
android.debugInformation,
android.strictAliasing,
android.fpu,
android.pic,
android.shortEnums,
android.cStandard,
android.cppStandard,
})
if _ACTION >= "vs2015" then
table.remove(elements, table.indexof(elements, vc2010.debugInformationFormat))
-- Android has C[pp]LanguageStandard instead.
table.remove(elements, table.indexof(elements, vc2010.languageStandard))
-- Ignore multiProcessorCompilation for android projects, they use UseMultiToolTask instead.
table.remove(elements, table.indexof(elements, vc2010.multiProcessorCompilation))
-- minimalRebuild also ends up in android projects somehow.
table.remove(elements, table.indexof(elements, vc2010.minimalRebuild))
-- VS has NEON support through EnableNeonCodegen.
table.replace(elements, vc2010.enableEnhancedInstructionSet, android.enableEnhancedInstructionSet)
-- precompiledHeaderFile support.
table.replace(elements, vc2010.precompiledHeaderFile, android.precompiledHeaderFile)
end
end
return elements
end)
function android.precompiledHeaderFile(fileName, cfg)
-- Doesn't work for project-relative paths.
vc2010.element("PrecompiledHeaderFile", nil, "%s", path.getabsolute(path.rebase(fileName, cfg.basedir, cfg.location)))
end
function android.debugInformation(cfg)
if cfg.flags.Symbols then
_p(3,'<GenerateDebugInformation>true</GenerateDebugInformation>')
end
end
function android.strictAliasing(cfg)
if cfg.strictaliasing ~= nil then
vc2010.element("StrictAliasing", nil, iif(cfg.strictaliasing == "Off", "false", "true"))
end
end
function android.fpu(cfg)
if cfg.fpu ~= nil then
_p(3,'<SoftFloat>true</SoftFloat>', iif(cfg.fpu == "Software", "true", "false"))
end
end
function android.pic(cfg)
if cfg.pic ~= nil then
vc2010.element("PositionIndependentCode", nil, iif(cfg.pic == "On", "true", "false"))
end
end
function android.verboseCompiler(cfg)
setBoolOption("Verbose", cfg.flags.VerboseCompiler, "true")
end
function android.undefineAllPreprocessorDefinitions(cfg)
setBoolOption("UndefineAllPreprocessorDefinitions", cfg.flags.UndefineAllPreprocessorDefinitions, "true")
end
function android.showIncludes(cfg)
setBoolOption("ShowIncludes", cfg.flags.ShowIncludes, "true")
end
function android.dataLevelLinking(cfg)
setBoolOption("DataLevelLinking", cfg.flags.DataLevelLinking, "true")
end
function android.shortEnums(cfg)
setBoolOption("UseShortEnums", cfg.flags.UseShortEnums, "true")
end
function android.cStandard(cfg)
local c_langmap = {
["C98"] = "c98",
["C99"] = "c99",
["C11"] = "c11",
["gnu99"] = "gnu99",
["gnu11"] = "gnu11",
}
if c_langmap[cfg.cdialect] ~= nil then
vc2010.element("CLanguageStandard", nil, c_langmap[cfg.cdialect])
end
end
function android.cppStandard(cfg)
local cpp_langmap = {
["C++98"] = "c++98",
["C++11"] = "c++11",
["C++14"] = "c++1y",
["C++17"] = "c++1z",
["C++latest"] = "c++1z",
["gnu++98"] = "gnu++98",
["gnu++11"] = "gnu++11",
["gnu++14"] = "gnu++1y",
["gnu++17"] = "gnu++1z",
}
if cpp_langmap[cfg.cppdialect] ~= nil then
vc2010.element("CppLanguageStandard", nil, cpp_langmap[cfg.cppdialect])
end
end
p.override(vc2010, "additionalCompileOptions", function(oldfn, cfg, condition)
if cfg.system == p.ANDROID then
local opts = cfg.buildoptions
if cfg.disablewarnings and #cfg.disablewarnings > 0 then
for _, warning in ipairs(cfg.disablewarnings) do
table.insert(opts, '-Wno-' .. warning)
end
end
-- -fvisibility=<>
if cfg.visibility ~= nil then
table.insert(opts, p.tools.gcc.cxxflags.visibility[cfg.visibility])
end
if #opts > 0 then
opts = table.concat(opts, " ")
vc2010.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts)
end
else
oldfn(cfg, condition)
end
end)
p.override(vc2010, "warningLevel", function(oldfn, cfg)
if _ACTION >= "vs2015" and cfg.system == p.ANDROID and cfg.warnings and cfg.warnings ~= "Off" then
vc2010.element("WarningLevel", nil, "EnableAllWarnings")
elseif (_ACTION >= "vs2015" and cfg.system == p.ANDROID and cfg.warnings) or not (_ACTION >= "vs2015" and cfg.system == p.ANDROID) then
oldfn(cfg)
end
end)
premake.override(vc2010, "clCompilePreprocessorDefinitions", function(oldfn, cfg, condition)
if cfg.system == p.ANDROID then
vc2010.preprocessorDefinitions(cfg, cfg.defines, false, condition)
else
oldfn(cfg, condition)
end
end)
premake.override(vc2010, "exceptionHandling", function(oldfn, cfg, condition)
if cfg.system == p.ANDROID then
-- Note: Android defaults to 'off'
local exceptions = {
On = "Enabled",
Off = "Disabled",
UnwindTables = "UnwindTables",
}
if _ACTION >= "vs2015" then
if exceptions[cfg.exceptionhandling] ~= nil then
vc2010.element("ExceptionHandling", condition, exceptions[cfg.exceptionhandling])
end
else
if cfg.exceptionhandling == premake.ON then
vc2010.element("GccExceptionHandling", condition, "true")
end
end
else
oldfn(cfg, condition)
end
end)
function android.enableEnhancedInstructionSet(cfg)
if cfg.vectorextensions == "NEON" then
vc2010.element("EnableNeonCodegen", nil, "true")
end
end
premake.override(vc2010, "runtimeTypeInfo", function(oldfn, cfg, condition)
if cfg.system == premake.ANDROID then
-- Note: Android defaults to 'off'
if cfg.rtti == premake.ON then
vc2010.element("RuntimeTypeInfo", condition, "true")
end
else
oldfn(cfg, condition)
end
end)
--
-- Extend Link.
--
premake.override(vc2010, "generateDebugInformation", function(oldfn, cfg)
-- Note: Android specifies the debug info in the clCompile section
if cfg.system ~= premake.ANDROID then
oldfn(cfg)
end
end)
--
-- Add android tools to vstudio actions.
--
premake.override(vc2010.elements, "itemDefinitionGroup", function(oldfn, cfg)
local elements = oldfn(cfg)
if cfg.system == premake.ANDROID and _ACTION < "vs2015" then
elements = table.join(elements, {
android.antBuild,
})
end
return elements
end)
function android.antPackage(cfg)
p.push('<AntPackage>')
if cfg.androidapplibname ~= nil then
vc2010.element("AndroidAppLibName", nil, cfg.androidapplibname)
else
vc2010.element("AndroidAppLibName", nil, "$(RootNamespace)")
end
p.pop('</AntPackage>')
end
function android.antBuild(cfg)
if cfg.kind == premake.STATICLIB or cfg.kind == premake.SHAREDLIB then
return
end
_p(2,'<AntBuild>')
_p(3,'<AntBuildType>%s</AntBuildType>', iif(premake.config.isDebugBuild(cfg), "Debug", "Release"))
_p(2,'</AntBuild>')
end
premake.override(vc2010, "additionalCompileOptions", function(oldfn, cfg, condition)
if cfg.system == premake.ANDROID then
vsandroid.additionalOptions(cfg, condition)
end
return oldfn(cfg, condition)
end)
premake.override(vc2010.elements, "user", function(oldfn, cfg)
if cfg.system == p.ANDROID then
return {}
else
return oldfn(cfg)
end
end)
--
-- Add options unsupported by vs-android UI to <AdvancedOptions>.
--
function vsandroid.additionalOptions(cfg)
if _ACTION >= "vs2015" then
else
local function alreadyHas(t, key)
for _, k in ipairs(t) do
if string.find(k, key) then
return true
end
end
return false
end
if not cfg.architecture or string.startswith(cfg.architecture, "arm") then
-- we might want to define the arch to generate better code
-- if not alreadyHas(cfg.buildoptions, "-march=") then
-- if cfg.architecture == "armv6" then
-- table.insert(cfg.buildoptions, "-march=armv6")
-- elseif cfg.architecture == "armv7" then
-- table.insert(cfg.buildoptions, "-march=armv7")
-- end
-- end
-- ARM has a comprehensive set of floating point options
if cfg.fpu ~= "Software" and cfg.floatabi ~= "soft" then
if cfg.architecture == "armv7" then
-- armv7 always has VFP, may not have NEON
if not alreadyHas(cfg.buildoptions, "-mfpu=") then
if cfg.vectorextensions == "NEON" then
table.insert(cfg.buildoptions, "-mfpu=neon")
elseif cfg.fpu == "Hardware" or cfg.floatabi == "softfp" or cfg.floatabi == "hard" then
table.insert(cfg.buildoptions, "-mfpu=vfpv3-d16") -- d16 is the lowest common denominator
end
end
if not alreadyHas(cfg.buildoptions, "-mfloat-abi=") then
if cfg.floatabi == "hard" then
table.insert(cfg.buildoptions, "-mfloat-abi=hard")
else
-- Android should probably use softfp by default for compatibility
table.insert(cfg.buildoptions, "-mfloat-abi=softfp")
end
end
else
-- armv5/6 may not have VFP
if not alreadyHas(cfg.buildoptions, "-mfpu=") then
if cfg.fpu == "Hardware" or cfg.floatabi == "softfp" or cfg.floatabi == "hard" then
table.insert(cfg.buildoptions, "-mfpu=vfp")
end
end
if not alreadyHas(cfg.buildoptions, "-mfloat-abi=") then
if cfg.floatabi == "softfp" then
table.insert(cfg.buildoptions, "-mfloat-abi=softfp")
elseif cfg.floatabi == "hard" then
table.insert(cfg.buildoptions, "-mfloat-abi=hard")
end
end
end
elseif cfg.floatabi == "soft" then
table.insert(cfg.buildoptions, "-mfloat-abi=soft")
end
if cfg.endian == "Little" then
table.insert(cfg.buildoptions, "-mlittle-endian")
elseif cfg.endian == "Big" then
table.insert(cfg.buildoptions, "-mbig-endian")
end
elseif cfg.architecture == "mips" then
-- TODO...
if cfg.vectorextensions == "MXU" then
table.insert(cfg.buildoptions, "-mmxu")
end
elseif cfg.architecture == "x86" then
-- TODO...
end
end
end
--
-- Disable subsystem.
--
p.override(vc2010, "subSystem", function(oldfn, cfg)
if cfg.system ~= p.ANDROID then
return oldfn(cfg)
end
end)
--
-- Remove .lib and list in LibraryDependencies instead of AdditionalDependencies.
--
p.override(vc2010, "additionalDependencies", function(oldfn, cfg, explicit)
if cfg.system == p.ANDROID then
local links = {}
-- If we need sibling projects to be listed explicitly, grab them first
if explicit then
links = config.getlinks(cfg, "siblings", "fullpath")
end
-- Then the system libraries, which come undecorated
local system = config.getlinks(cfg, "system", "name")
for i = 1, #system do
local link = system[i]
table.insert(links, link)
end
-- TODO: When to use LibraryDependencies vs AdditionalDependencies
if #links > 0 then
links = path.translate(table.concat(links, ";"))
vc2010.element("LibraryDependencies", nil, "%%(LibraryDependencies);%s", links)
end
else
return oldfn(cfg, explicit)
end
end)
function android.useMultiToolTask(cfg)
-- Android equivalent of 'MultiProcessorCompilation'
if cfg.flags.MultiProcessorCompile then
vc2010.element("UseMultiToolTask", nil, "true")
end
end
premake.override(vc2010.elements, "outputProperties", function(oldfn, cfg)
if cfg.system == p.ANDROID then
return table.join(oldfn(cfg), {
android.useMultiToolTask,
})
else
return oldfn(cfg)
end
end)
--
-- Disable override of OutDir. This is breaking deployment.
--
p.override(vc2010, "outDir", function(oldfn, cfg)
if cfg.system ~= p.ANDROID then
return oldfn(cfg)
end
end)

View File

@@ -0,0 +1,38 @@
--
-- android/vsandroid_vstudio.lua
-- vs-android integration for vstudio.
-- Copyright (c) 2012-2015 Manu Evans and the Premake project
--
local p = premake
local android = p.modules.android
local vsandroid = p.modules.vsandroid
local vstudio = p.vstudio
--
-- Add android tools to vstudio actions.
--
premake.override(vstudio, "solutionPlatform", function (oldfn, cfg)
local platform = oldfn(cfg)
-- Bypass that pesky Win32 hack
if cfg.system == premake.ANDROID and _ACTION >= "vs2015" then
if cfg.platform == "x86" then
platform = "x86"
end
end
return platform
end)
premake.override(vstudio, "archFromConfig", function (oldfn, cfg, win32)
-- Bypass that pesky Win32 hack by not passing win32 down
if cfg.system == premake.ANDROID and _ACTION >= "vs2015" then
return oldfn(cfg)
end
return oldfn(cfg, win32)
end)

View File

@@ -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.

View File

@@ -0,0 +1,6 @@
return {
"_preload.lua",
"codelite.lua",
"codelite_workspace.lua",
"codelite_project.lua",
}

View File

@@ -0,0 +1,58 @@
--
-- 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",
toolset = "clang",
-- 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

View File

@@ -0,0 +1,86 @@
--
-- Name: codelite/codelite.lua
-- Purpose: Define the CodeLite action(s).
-- Author: Ryan Pusztai
-- Modified by: Andrea Zanellato
-- Andrew Gough
-- Manu Evans
-- Jason Perkins
-- Created: 2013/05/06
-- Copyright: (c) 2008-2020 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
-- Codelite breaks if "|" is used here, see #1411
cfgname = string.format("%s-%s", cfg.platform, cfg.buildcfg)
end
return cfgname
end
-- Element text is not escaped the same as element attributes
function codelite.escElementText(value)
local result = value:gsub('&', '&amp;')
result = result:gsub('<', '&lt;')
result = result:gsub('>', '&gt;')
return result
end
function codelite.esc(value)
local result = value:gsub('&', '&amp;')
result = result:gsub('<', '&lt;')
result = result:gsub('>', '&gt;')
result = result:gsub('"', '&quot;')
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.isc(prj) or 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

View File

@@ -0,0 +1,529 @@
--
-- Name: codelite/codelite_project.lua
-- Purpose: Generate a CodeLite C/C++ project file.
-- Author: Ryan Pusztai
-- Modified by: Andrea Zanellato
-- Manu Evans
-- Tom van Dijck
-- Created: 2013/05/06
-- Copyright: (c) 2008-2016 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 p.languages.isc(cfg.language) then
return m.ctools[tool]
elseif p.languages.iscpp(cfg.language) 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('<?xml version="1.0" encoding="UTF-8"?>')
local type = m.internalTypeMap[prj.kind] or ""
_x('<CodeLite_Project Name="%s" InternalType="%s">', prj.name, type)
end
function m.plugins(prj)
-- _p(1, '<Plugins>')
-- <Plugin Name="CMakePlugin">
-- <Plugin Name="qmake">
-- _p(1, '</Plugins>')
_p(1, '<Plugins/>')
end
function m.description(prj)
_p(1, '<Description/>')
-- 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, '<VirtualDirectory Name="%s">', node.name)
end,
onbranchexit = function(node, depth)
_p(depth, '</VirtualDirectory>')
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, '<File Name="%s" ExcludeProjConfig="%s" />', node.relpath, table.concat(excludesFromBuild, ';'))
else
_p(depth, '<File Name="%s"/>', node.relpath)
end
end,
}, true)
end
function m.dependencies(prj)
-- TODO: dependencies don't emit a line for each config if there aren't any...
-- _p(1, '<Dependencies/>')
local dependencies = project.getdependencies(prj)
for cfg in project.eachconfig(prj) do
cfgname = codelite.cfgname(cfg)
if #dependencies > 0 then
_p(1, '<Dependencies Name="%s">', cfgname)
for _, dependency in ipairs(dependencies) do
_p(2, '<Project Name="%s"/>', dependency.name)
end
_p(1, '</Dependencies>')
else
_p(1, '<Dependencies Name="%s"/>', cfgname)
end
end
end
function m.global_compiler(prj)
_p(3, '<Compiler Options="" C_Options="" Assembler="">')
_p(4, '<IncludePath Value="."/>')
_p(3, '</Compiler>')
end
function m.global_linker(prj)
_p(3, '<Linker Options="">')
_p(4, '<LibraryPath Value="."/>')
_p(3, '</Linker>')
end
function m.global_resourceCompiler(prj)
_p(3, '<ResourceCompiler Options=""/>')
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, '<Compiler Required="no"/>')
return
end
local toolset = m.getcompiler(cfg)
local sysincludedirs = toolset.getincludedirs(cfg, {}, cfg.sysincludedirs, cfg.frameworkdirs)
local forceincludes = toolset.getforceincludes(cfg)
local cxxflags = table.concat(table.join(sysincludedirs, toolset.getcxxflags(cfg), forceincludes, cfg.buildoptions), ";")
local cflags = table.concat(table.join(sysincludedirs, toolset.getcflags(cfg), forceincludes, cfg.buildoptions), ";")
local asmflags = ""
local pch = p.tools.gcc.getpch(cfg)
local usepch = "yes"
if pch == nil then
pch = "";
usepch = "no"
end
_x(3, '<Compiler Options="%s" C_Options="%s" Assembler="%s" Required="yes" PreCompiledHeader="%s" PCHInCommandLine="%s" UseDifferentPCHFlags="no" PCHFlags="">', cxxflags, cflags, asmflags, pch, usepch)
for _, includedir in ipairs(cfg.includedirs) do
_x(4, '<IncludePath Value="%s"/>', project.getrelative(cfg.project, includedir))
end
for _, define in ipairs(cfg.defines) do
_p(4, '<Preprocessor Value="%s"/>', p.esc(define):gsub(' ', '\\ '))
end
_p(3, '</Compiler>')
end
function m.linker(cfg)
if configuration_iscustombuild(cfg) or configuration_isfilelist(cfg) then
_p(3, '<Linker Required="no"/>')
return
end
local toolset = m.getcompiler(cfg)
local flags = table.join(toolset.getldflags(cfg), toolset.getincludedirs(cfg, {}, nil, cfg.frameworkdirs), toolset.getrunpathdirs(cfg, table.join(cfg.runpathdirs, config.getsiblingtargetdirs(cfg))), cfg.linkoptions, toolset.getlinks(cfg))
_x(3, '<Linker Required="yes" Options="%s">', table.concat(flags, ";"))
for _, libdir in ipairs(cfg.libdirs) do
_p(4, '<LibraryPath Value="%s"/>', project.getrelative(cfg.project, libdir))
end
_p(3, '</Linker>')
end
function m.resourceCompiler(cfg)
if not configuration_needresoptions(cfg) then
_p(3, '<ResourceCompiler Options="" Required="no"/>')
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, '<ResourceCompiler Options="%s%s" Required="yes">', defines, options)
for _, includepath in ipairs(table.join(cfg.sysincludedirs, cfg.includedirs, cfg.resincludedirs)) do
_x(4, '<IncludePath Value="%s"/>', project.getrelative(cfg.project, includepath))
end
_p(3, '</ResourceCompiler>')
end
function m.general(cfg)
if configuration_isfilelist(cfg) then
_p(3, '<General IntermediateDirectory="." WorkingDirectory="." PauseExecWhenProcTerminates="no"/>')
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 workingdir = cfg.debugdir or prj.location
local command = iif(isExe, path.getrelative(workingdir, cfg.buildtarget.abspath), "")
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, '<General OutputFile="%s" IntermediateDirectory="%s" Command="%s" CommandArguments="%s" UseSeparateDebugArgs="%s" DebugArguments="%s" WorkingDirectory="%s" PauseExecWhenProcTerminates="%s" IsGUIProgram="%s" IsEnabled="%s"/>',
targetname, objdir, command, cmdargs, useseparatedebugargs, debugargs, workingdir, pauseexec, isguiprogram, isenabled)
end
function m.environment(cfg)
local envs = table.concat(cfg.debugenvs, "\n")
_p(3, '<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">')
_p(4, '<![CDATA[%s]]>', envs)
_p(3, '</Environment>')
end
function m.debugger(cfg)
_p(3, '<Debugger IsRemote="%s" RemoteHostName="%s" RemoteHostPort="%s" DebuggerPath="" IsExtended="%s">', 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.escaper(codelite.escElementText)
_p(4, '<DebuggerSearchPaths>%s</DebuggerSearchPaths>', table.concat(p.esc(project.getrelative(cfg.project, cfg.debugsearchpaths)), "\n"))
p.escaper(codelite.esc)
else
_p(4, '<DebuggerSearchPaths/>')
end
if #cfg.debugconnectcommands > 0 then
p.escaper(codelite.escElementText)
_p(4, '<PostConnectCommands>%s</PostConnectCommands>', table.concat(p.esc(cfg.debugconnectcommands), "\n"))
p.escaper(codelite.esc)
else
_p(4, '<PostConnectCommands/>')
end
if #cfg.debugstartupcommands > 0 then
p.escaper(codelite.escElementText)
_p(4, '<StartupCommands>%s</StartupCommands>', table.concat(p.esc(cfg.debugstartupcommands), "\n"))
p.escaper(codelite.esc)
else
_p(4, '<StartupCommands/>')
end
_p(3, '</Debugger>')
end
function m.preBuild(cfg)
if #cfg.prebuildcommands > 0 or cfg.prebuildmessage then
_p(3, '<PreBuild>')
p.escaper(codelite.escElementText)
if cfg.prebuildmessage then
local command = os.translateCommandsAndPaths("@{ECHO} " .. cfg.prebuildmessage, cfg.project.basedir, cfg.project.location)
_x(4, '<Command Enabled="yes">%s</Command>', command)
end
local commands = os.translateCommandsAndPaths(cfg.prebuildcommands, cfg.project.basedir, cfg.project.location)
for _, command in ipairs(commands) do
_x(4, '<Command Enabled="yes">%s</Command>', command)
end
p.escaper(codelite.esc)
_p(3, '</PreBuild>')
end
end
function m.postBuild(cfg)
if #cfg.postbuildcommands > 0 or cfg.postbuildmessage then
_p(3, '<PostBuild>')
p.escaper(codelite.escElementText)
if cfg.postbuildmessage then
local command = os.translateCommandsAndPaths("@{ECHO} " .. cfg.postbuildmessage, cfg.project.basedir, cfg.project.location)
_x(4, '<Command Enabled="yes">%s</Command>', command)
end
local commands = os.translateCommandsAndPaths(cfg.postbuildcommands, cfg.project.basedir, cfg.project.location)
for _, command in ipairs(commands) do
_x(4, '<Command Enabled="yes">%s</Command>', command)
end
p.escaper(codelite.esc)
_p(3, '</PostBuild>')
end
end
function m.customBuild(cfg)
if not configuration_iscustombuild(cfg) then
_p(3, '<CustomBuild Enabled="no"/>')
return
end
local build = table.implode(cfg.buildcommands,"","","")
local clean = table.implode(cfg.cleancommands,"","","")
local rebuild = table.implode(cfg.rebuildcommands,"","","")
_p(3, '<CustomBuild Enabled="yes">')
_x(4, '<BuildCommand>%s</BuildCommand>', build)
_x(4, '<CleanCommand>%s</CleanCommand>', clean)
_x(4, '<RebuildCommand>%s</RebuildCommand>', rebuild)
_p(4, '<PreprocessFileCommand></PreprocessFileCommand>')
_p(4, '<SingleFileCommand></SingleFileCommand>')
_p(4, '<MakefileGenerationCommand></MakefileGenerationCommand>')
_p(4, '<ThirdPartyToolName></ThirdPartyToolName>')
_p(4, '<WorkingDirectory></WorkingDirectory>')
_p(3, '</CustomBuild>')
end
function m.additionalRules(cfg)
if configuration_iscustombuild(cfg) then
_p(3, '<AdditionalRules/>')
return
end
_p(3, '<AdditionalRules>')
_p(4, '<CustomPostBuild/>')
local dependencies = {}
local makefilerules = {}
local function addrule(dependencies, makefilerules, config, filename)
if #config.buildcommands == 0 or #config.buildOutputs == 0 then
return false
end
local inputs = table.implode(project.getrelative(cfg.project, config.buildInputs), "", "", " ")
if filename ~= "" and inputs ~= "" then
filename = filename .. " "
end
local outputs = project.getrelative(cfg.project, config.buildOutputs[1])
local buildmessage = ""
if config.buildmessage then
buildmessage = "\t@{ECHO} " .. config.buildmessage .. "\n"
end
local commands = table.implode(config.buildCommands,"\t","\n","")
table.insert(makefilerules, os.translateCommandsAndPaths(outputs .. ": " .. filename .. inputs .. "\n" .. buildmessage .. commands, cfg.project.basedir, cfg.project.location))
table.insertflat(dependencies, outputs)
return true
end
local tr = project.getsourcetree(cfg.project)
p.tree.traverse(tr, {
onleaf = function(node, depth)
local filecfg = p.fileconfig.getconfig(node, cfg)
local prj = cfg.project
local rule = p.global.getRuleForFile(node.name, prj.rules)
if not addrule(dependencies, makefilerules, filecfg, node.relpath) and rule then
local environ = table.shallowcopy(filecfg.environ)
if rule.propertydefinition then
p.rule.prepareEnvironment(rule, environ, cfg)
p.rule.prepareEnvironment(rule, environ, filecfg)
end
local rulecfg = p.context.extent(rule, environ)
addrule(dependencies, makefilerules, rulecfg, node.relpath)
end
end
})
addrule(dependencies, makefilerules, cfg, "")
if #makefilerules == 0 and #dependencies == 0 then
_p(4, '<CustomPreBuild/>')
else
_p(4, '<CustomPreBuild>' .. table.implode(dependencies,"",""," "))
_p(0, table.implode(makefilerules,"","","\n") .. '</CustomPreBuild>')
end
_p(3, '</AdditionalRules>')
end
function m.isCpp11(cfg)
return (cfg.cppdialect == 'gnu++11') or (cfg.cppdialect == 'C++11') or (cfg.cppdialect == 'gnu++0x') or (cfg.cppdialect == 'C++0x')
end
function m.isCpp14(cfg)
return (cfg.cppdialect == 'gnu++14') or (cfg.cppdialect == 'C++14') or (cfg.cppdialect == 'gnu++1y') or (cfg.cppdialect == 'C++1y')
end
function m.completion(cfg)
_p(3, '<Completion EnableCpp11="%s" EnableCpp14="%s">',
iif(m.isCpp11(cfg), "yes", "no"),
iif(m.isCpp14(cfg), "yes", "no")
)
_p(4, '<ClangCmpFlagsC/>')
_p(4, '<ClangCmpFlags/>')
_p(4, '<ClangPP/>') -- TODO: we might want to set special code completion macros...?
_p(4, '<SearchPaths/>') -- TODO: search paths for code completion?
_p(3, '</Completion>')
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, '<Settings Type="%s">', m.types[prj.kind] or "")
_p(2, '<GlobalSettings>')
p.callArray(m.elements.globalSettings, prj)
_p(2, '</GlobalSettings>')
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, '<Configuration Name="%s" CompilerType="%s" DebuggerType="%s" Type="%s" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">', cfgname, compiler, debugger, type)
p.callArray(m.elements.settings, cfg)
_p(2, '</Configuration>')
end
_p(1, '</Settings>')
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('</CodeLite_Project>')
end

View File

@@ -0,0 +1,105 @@
--
-- 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.w('<?xml version="1.0" encoding="UTF-8"?>')
local tagsdb = ""
-- local tagsdb = "./" .. wks.name .. ".tags"
p.push('<CodeLite_Workspace Name="%s" Database="%s" SWTLW="No">', 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)
if (prj.name == wks.startproject) then
p.w('<Project Name="%s" Path="%s" Active="Yes"/>', prj.name, prjpath)
else
p.w('<Project Name="%s" Path="%s"/>', prj.name, prjpath)
end
end,
onbranchenter = function(n)
p.push('<VirtualDirectory Name="%s">', n.name)
end,
onbranchexit = function(n)
p.pop('</VirtualDirectory>')
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.push('<BuildMatrix>')
local selected = "yes" -- only one configuration should be selected
for cfg in workspace.eachconfig(wks) do
local cfgname = codelite.cfgname(cfg)
p.push('<WorkspaceConfiguration Name="%s" Selected="%s">', cfgname, selected)
selected = "no"
local tr = workspace.grouptree(wks)
tree.traverse(tr, {
onleaf = function(n)
local prj = n.project
p.w('<Project Name="%s" ConfigName="%s"/>', prj.name, cfgname)
end
})
p.pop('</WorkspaceConfiguration>')
end
p.pop('</BuildMatrix>')
p.pop('</CodeLite_Workspace>')
end

View File

@@ -0,0 +1,8 @@
require ("codelite")
return {
"test_codelite_workspace.lua",
"test_codelite_project.lua",
"test_codelite_config.lua",
"test_codelite_additional_rules.lua",
}

View File

@@ -0,0 +1,256 @@
---
-- codelite/tests/test_codelite_config.lua
-- Automated test suite for CodeLite project generation.
-- Copyright (c) 2021 Joris Dauphin and the Premake project
---
local suite = test.declare("codelite_cproj_additional_rules")
local p = premake
local codelite = p.modules.codelite
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
local function prepare_rule()
rule "TestRule"
display "Test Rule"
fileextension ".rule"
propertydefinition {
name = "TestProperty",
kind = "boolean",
value = false,
switch = "-p"
}
propertydefinition {
name = "TestProperty2",
kind = "boolean",
value = false,
switch = "-p2"
}
propertydefinition {
name = "TestListProperty",
kind = "list"
}
propertydefinition {
name = "TestListPropertyWithSwitch",
kind = "list",
switch = "-S"
}
propertydefinition {
name = "TestListPropertySeparator",
kind = "list",
separator = ","
}
propertydefinition {
name = "TestListPropertySeparatorWithSwitch",
kind = "list",
separator = ",",
switch = "-O"
}
propertydefinition {
name = "TestEnumProperty",
values = { [0] = "V0", [1] = "V1"},
switch = { [0] = "S0", [1] = "S1"},
value = 0
}
buildmessage 'Rule-ing %{file.name}'
buildcommands 'dorule %{TestProperty} %{TestProperty2} %{TestListProperty} %{TestListPropertyWithSwitch} %{TestListPropertySeparator} %{TestListPropertySeparatorWithSwitch} %{TestEnumProperty} "%{file.path}"'
buildoutputs { "%{file.basename}.obj" }
end
function suite.setup()
p.action.set("codelite")
p.escaper(codelite.esc)
p.indent(" ")
prepare_rule()
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
cfg = test.getconfig(prj, "Debug")
end
function suite.customRuleEmpty()
prepare()
codelite.project.additionalRules(prj)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild/>
</AdditionalRules>
]]
end
function suite.customRuleWithPropertyDefinition()
rules { "TestRule" }
files { "test.rule", "test2.rule" }
testRuleVars {
TestProperty = true
}
filter "files:test2.rule"
testRuleVars {
TestProperty2 = true
}
prepare()
codelite.project.additionalRules(cfg)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild>test.obj test2.obj
test.obj: test.rule
@echo Rule-ing test.rule
dorule -p "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
dorule -p -p2 "test2.rule"
</CustomPreBuild>
</AdditionalRules>
]]
end
function suite.customRuleWithPropertyDefinitionSeparator()
rules { "TestRule" }
files { "test.rule", "test2.rule", "test3.rule", "test4.rule" }
filter "files:test.rule"
testRuleVars {
TestListProperty = { "testValue1", "testValue2" }
}
filter "files:test2.rule"
testRuleVars {
TestListPropertyWithSwitch = { "testValue1", "testValue2" }
}
filter "files:test3.rule"
testRuleVars {
TestListPropertySeparator = { "testValue1", "testValue2" }
}
filter "files:test4.rule"
testRuleVars {
TestListPropertySeparatorWithSwitch = { "testValue1", "testValue2" }
}
prepare()
codelite.project.additionalRules(cfg)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild>test.obj test2.obj test3.obj test4.obj
test.obj: test.rule
@echo Rule-ing test.rule
dorule testValue1 testValue2 "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
dorule -StestValue1 -StestValue2 "test2.rule"
test3.obj: test3.rule
@echo Rule-ing test3.rule
dorule testValue1,testValue2 "test3.rule"
test4.obj: test4.rule
@echo Rule-ing test4.rule
dorule -OtestValue1,testValue2 "test4.rule"
</CustomPreBuild>
</AdditionalRules>
]]
end
function suite.customRuleWithPropertyDefinitionEnum()
rules { "TestRule" }
files { "test.rule", "test2.rule" }
testRuleVars {
TestEnumProperty = "V0"
}
filter "files:test2.rule"
testRuleVars {
TestEnumProperty = "V1"
}
prepare()
codelite.project.additionalRules(cfg)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild>test.obj test2.obj
test.obj: test.rule
@echo Rule-ing test.rule
dorule S0 "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
dorule S1 "test2.rule"
</CustomPreBuild>
</AdditionalRules>
]]
end
function suite.buildCommand()
files {"foo.txt", "bar.txt"}
buildinputs { "toto.txt", "extra_dependency" }
buildoutputs { "toto.c" }
buildcommands { "test", "test toto.c" }
buildmessage "Some message"
prepare()
codelite.project.additionalRules(cfg)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild>toto.c
toto.c: toto.txt extra_dependency
@echo Some message
test
test toto.c
</CustomPreBuild>
</AdditionalRules>]]
end
function suite.buildCommandPerFile()
files {"foo.txt", "bar.txt"}
filter "files:**.txt"
buildinputs { "%{file.basename}.h", "extra_dependency" }
buildoutputs { "%{file.basename}.c" }
buildcommands { "test", "test %{file.basename}" }
buildmessage "Some message"
prepare()
codelite.project.additionalRules(cfg)
test.capture [[
<AdditionalRules>
<CustomPostBuild/>
<CustomPreBuild>bar.c foo.c
bar.c: bar.txt bar.h extra_dependency
@echo Some message
test
test bar
foo.c: foo.txt foo.h extra_dependency
@echo Some message
test
test foo
</CustomPreBuild>
</AdditionalRules>]]
end

View File

@@ -0,0 +1,377 @@
---
-- 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 p = premake
local codelite = p.modules.codelite
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.action.set("codelite")
p.escaper(codelite.esc)
p.indent(" ")
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks,1)
cfg = test.getconfig(prj, "Debug")
end
function suite.OnProjectCfg_Compiler()
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end
function suite.OnProjectCfg_Flags()
optimize "Debug"
exceptionhandling "Off"
rtti "Off"
pic "On"
symbols "On"
language "C++"
cppdialect "C++11"
flags { "NoBufferSecurityCheck" }
forceincludes { "forced_include1.h", "forced_include2.h" }
buildoptions { "-opt1", "-opt2" }
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="-O0;-fPIC;-g;-std=c++11;-fno-exceptions;-fno-stack-protector;-fno-rtti;-include forced_include1.h;-include forced_include2.h;-opt1;-opt2" C_Options="-O0;-fPIC;-g;-include forced_include1.h;-include forced_include2.h;-opt1;-opt2" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end
function suite.OnProjectCfg_Includes()
includedirs { "dir/", "dir2" }
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
<IncludePath Value="dir"/>
<IncludePath Value="dir2"/>
</Compiler>
]]
end
function suite.OnProjectCfg_SysIncludes()
sysincludedirs { "sysdir", "sysdir2/"}
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="-isystem sysdir;-isystem sysdir2" C_Options="-isystem sysdir;-isystem sysdir2" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end
function suite.OnProjectCfg_Defines()
defines { "TEST", "DEF", "VAL=1", "ESCAPE=\"WITH SPACE\"" }
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
<Preprocessor Value="TEST"/>
<Preprocessor Value="DEF"/>
<Preprocessor Value="VAL=1"/>
<Preprocessor Value="ESCAPE=&quot;WITH\ SPACE&quot;"/>
</Compiler>
]]
end
function suite.OnProjectCfg_Pch()
pchheader "pch.h"
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="pch.h" PCHInCommandLine="yes" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end
function suite.OnProjectCfg_Linker()
prepare()
codelite.project.linker(cfg)
test.capture [[
<Linker Required="yes" Options="">
</Linker>
]]
end
function suite.OnProjectCfg_LibPath()
libdirs { "test/", "test2" }
prepare()
codelite.project.linker(cfg)
test.capture [[
<Linker Required="yes" Options="">
<LibraryPath Value="test"/>
<LibraryPath Value="test2"/>
</Linker>
]]
end
function suite.OnProjectCfg_Libs()
links { "a", "b" }
prepare()
codelite.project.linker(cfg)
test.capture [[
<Linker Required="yes" Options="-la;-lb">
</Linker>
]]
end
-- TODO: test sibling lib project links
function suite.OnProjectCfg_ResCompiler()
prepare()
codelite.project.resourceCompiler(cfg)
test.capture [[
<ResourceCompiler Options="" Required="no"/>
]]
end
function suite.OnProjectCfg_ResInclude()
files { "x.rc" }
resincludedirs { "dir/" }
prepare()
codelite.project.resourceCompiler(cfg)
test.capture [[
<ResourceCompiler Options="" Required="yes">
<IncludePath Value="dir"/>
</ResourceCompiler>
]]
end
function suite.OnProjectCfg_ResRegularInclude()
files { "x.rc" }
includedirs { "regulardir/" }
prepare()
codelite.project.resourceCompiler(cfg)
test.capture [[
<ResourceCompiler Options="" Required="yes">
<IncludePath Value="regulardir"/>
</ResourceCompiler>
]]
end
function suite.OnProjectCfg_ResSysInclude()
files { "x.rc" }
sysincludedirs { "sysdir/" }
prepare()
codelite.project.resourceCompiler(cfg)
test.capture [[
<ResourceCompiler Options="" Required="yes">
<IncludePath Value="sysdir"/>
</ResourceCompiler>
]]
end
function suite.OnProjectCfg_PreBuildMessage()
prebuildmessage "test"
prepare()
codelite.project.preBuild(cfg)
test.capture [[
<PreBuild>
<Command Enabled="yes">@echo test</Command>
</PreBuild>
]]
end
function suite.OnProjectCfg_PostBuildMessage()
postbuildmessage "test"
prepare()
codelite.project.postBuild(cfg)
test.capture [[
<PostBuild>
<Command Enabled="yes">@echo test</Command>
</PostBuild>
]]
end
function suite.OnProjectCfg_General()
system "Windows"
prepare()
codelite.project.general(cfg)
test.capture [[
<General OutputFile="bin/Debug/MyProject.exe" IntermediateDirectory="obj/Debug" Command="bin/Debug/MyProject.exe" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
]]
end
function suite.OnProjectCfg_Environment()
debugenvs { "ENV_ONE=1", "ENV_TWO=2" }
prepare()
codelite.project.environment(cfg)
test.capture(
' <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">\n' ..
' <![CDATA[ENV_ONE=1\n' ..
'ENV_TWO=2]]>\n' ..
' </Environment>'
)
end
function suite.OnProjectCfg_EnvironmentEscaping()
debugenvs { "\"ENV\"=<&>" }
prepare()
codelite.project.environment(cfg)
test.capture(
' <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">\n' ..
' <![CDATA["ENV"=<&>]]>\n' ..
' </Environment>'
)
end
function suite.OnProjectCfg_Debugger()
prepare()
codelite.project.debugger(cfg)
test.capture [[
<Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
<DebuggerSearchPaths/>
<PostConnectCommands/>
<StartupCommands/>
</Debugger>
]]
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 [[
<Debugger IsRemote="yes" RemoteHostName="localhost" RemoteHostPort="2345" DebuggerPath="" IsExtended="yes">
<DebuggerSearchPaths>search
path</DebuggerSearchPaths>
<PostConnectCommands>connectcmd1
cmd2</PostConnectCommands>
<StartupCommands>startcmd1
cmd2</StartupCommands>
</Debugger>
]]
end
function suite.OnProjectCfg_DebuggerOptsEscaping()
debugremotehost "localhost"
debugport(2345)
debugextendedprotocol(true)
debugsearchpaths { "\"search\" && <path>" }
debugconnectcommands { "\"connect\" && <cmd>" }
debugstartupcommands { "\"start\" && <cmd>" }
prepare()
codelite.project.debugger(cfg)
test.capture [[
<Debugger IsRemote="yes" RemoteHostName="localhost" RemoteHostPort="2345" DebuggerPath="" IsExtended="yes">
<DebuggerSearchPaths>"search" &amp;&amp; &lt;path&gt;</DebuggerSearchPaths>
<PostConnectCommands>"connect" &amp;&amp; &lt;cmd&gt;</PostConnectCommands>
<StartupCommands>"start" &amp;&amp; &lt;cmd&gt;</StartupCommands>
</Debugger>
]]
end
function suite.OnProjectCfg_PreBuild()
prebuildcommands { "cmd0", "cmd1" }
prepare()
codelite.project.preBuild(prj)
test.capture [[
<PreBuild>
<Command Enabled="yes">cmd0</Command>
<Command Enabled="yes">cmd1</Command>
</PreBuild>
]]
end
function suite.OnProjectCfg_PreBuild_Escaped()
prebuildcommands {
"touch \"./build/copyright\" && echo OK",
"cat \"./lib/copyright\" >> \"./build/copyright\""
}
prepare()
codelite.project.preBuild(prj)
test.capture [[
<PreBuild>
<Command Enabled="yes">touch "./build/copyright" &amp;&amp; echo OK</Command>
<Command Enabled="yes">cat "./lib/copyright" &gt;&gt; "./build/copyright"</Command>
</PreBuild>
]]
end
function suite.OnProjectCfg_PostBuild()
postbuildcommands { "cmd0", "cmd1" }
prepare()
codelite.project.postBuild(prj)
test.capture [[
<PostBuild>
<Command Enabled="yes">cmd0</Command>
<Command Enabled="yes">cmd1</Command>
</PostBuild>
]]
end
function suite.OnProjectCfg_PostBuild_Escaped()
postbuildcommands {
"touch \"./build/copyright\" && echo OK",
"cat \"./lib/copyright\" >> \"./build/copyright\""
}
prepare()
codelite.project.postBuild(prj)
test.capture [[
<PostBuild>
<Command Enabled="yes">touch "./build/copyright" &amp;&amp; echo OK</Command>
<Command Enabled="yes">cat "./lib/copyright" &gt;&gt; "./build/copyright"</Command>
</PostBuild>
]]
end
function suite.OnProjectCfg_Completion()
language "C++"
cppdialect "C++11"
prepare()
codelite.project.completion(prj)
test.capture [[
<Completion EnableCpp11="yes" EnableCpp14="no">
<ClangCmpFlagsC/>
<ClangCmpFlags/>
<ClangPP/>
<SearchPaths/>
</Completion>
]]
end
function suite.OnProjectCfg_UnsignedCharOn()
unsignedchar "On"
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="-funsigned-char" C_Options="-funsigned-char" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end
function suite.OnProjectCfg_UnsignedCharOff()
unsignedchar "Off"
prepare()
codelite.project.compiler(cfg)
test.capture [[
<Compiler Options="-fno-unsigned-char" C_Options="-fno-unsigned-char" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
</Compiler>
]]
end

View File

@@ -0,0 +1,102 @@
---
-- 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 p = premake
local codelite = p.modules.codelite
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj
function suite.setup()
p.action.set("codelite")
p.escaper(codelite.esc)
p.indent(" ")
wks = test.createWorkspace()
end
local function prepare()
wks = p.oven.bakeWorkspace(wks)
prj = test.getproject(wks, 1)
end
function suite.OnProject_Header()
prepare()
codelite.project.header(prj)
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="MyProject" InternalType="Console">
]]
end
function suite.OnProject_Header_Windowed()
kind "WindowedApp"
prepare()
codelite.project.header(prj)
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="MyProject" InternalType="Console">
]]
end
function suite.OnProject_Header_Shared()
kind "SharedLib"
prepare()
codelite.project.header(prj)
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Project Name="MyProject" InternalType="Library">
]]
end
function suite.OnProject_Plugins()
prepare()
codelite.project.plugins(prj)
test.capture [[
<Plugins/>
]]
end
function suite.OnProject_Description()
prepare()
codelite.project.description(prj)
test.capture [[
<Description/>
]]
end
function suite.OnProject_Dependencies()
prepare()
codelite.project.dependencies(prj)
test.capture [[
<Dependencies Name="Debug"/>
<Dependencies Name="Release"/>
]]
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 [[
<Settings Type="Executable">
<GlobalSettings>
<Compiler Options="" C_Options="" Assembler="">
<IncludePath Value="."/>
</Compiler>
<Linker Options="">
<LibraryPath Value="."/>
</Linker>
<ResourceCompiler Options=""/>
</GlobalSettings>
]]
end

View File

@@ -0,0 +1,224 @@
---
-- 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 p = premake
local codelite = p.modules.codelite
--
-- Setup
--
local wks, prj
function suite.setup()
p.action.set("codelite")
p.escaper(codelite.esc)
p.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 [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]]
end
function suite.onDefaultWorkspace()
prepare()
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="MyProject.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyProject" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyProject" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]]
end
function suite.onMultipleProjects()
test.createproject(wks)
prepare()
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="MyProject.project"/>
<Project Name="MyProject2" Path="MyProject2.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyProject" ConfigName="Debug"/>
<Project Name="MyProject2" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyProject" ConfigName="Release"/>
<Project Name="MyProject2" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]]
end
--
-- Projects should include relative path from workspace.
--
function suite.onNestedProjectPath()
location "MyProject"
prepare()
test.capture([[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="MyProject/MyProject.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyProject" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyProject" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]])
end
function suite.onExternalProjectPath()
location "../MyProject"
prepare()
test.capture([[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="../MyProject/MyProject.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyProject" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyProject" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]])
end
function suite.onActiveProject()
workspace("MyWorkspace")
startproject "MyProject"
prepare()
test.capture([[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="MyProject.project" Active="Yes"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyProject" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyProject" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]])
end
function suite.onGroupedProjects()
wks.projects = {}
project "MyGrouplessProject"
group "MyGroup"
project "MyGroupedProject"
group "My/Nested/Group"
project "MyNestedGroupedProject"
prepare()
test.capture([[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<VirtualDirectory Name="My">
<VirtualDirectory Name="Nested">
<VirtualDirectory Name="Group">
<Project Name="MyNestedGroupedProject" Path="MyNestedGroupedProject.project"/>
</VirtualDirectory>
</VirtualDirectory>
</VirtualDirectory>
<VirtualDirectory Name="MyGroup">
<Project Name="MyGroupedProject" Path="MyGroupedProject.project"/>
</VirtualDirectory>
<Project Name="MyGrouplessProject" Path="MyGrouplessProject.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="Debug" Selected="yes">
<Project Name="MyNestedGroupedProject" ConfigName="Debug"/>
<Project Name="MyGroupedProject" ConfigName="Debug"/>
<Project Name="MyGrouplessProject" ConfigName="Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="Release" Selected="no">
<Project Name="MyNestedGroupedProject" ConfigName="Release"/>
<Project Name="MyGroupedProject" ConfigName="Release"/>
<Project Name="MyGrouplessProject" ConfigName="Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]])
end
---
-- Test handling of platforms
---
function suite.onPlatforms()
workspace "MyWorkspace"
platforms { "x86_64", "x86" }
prepare()
test.capture [[
<?xml version="1.0" encoding="UTF-8"?>
<CodeLite_Workspace Name="MyWorkspace" Database="" SWTLW="No">
<Project Name="MyProject" Path="MyProject.project"/>
<BuildMatrix>
<WorkspaceConfiguration Name="x86_64-Debug" Selected="yes">
<Project Name="MyProject" ConfigName="x86_64-Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="x86-Debug" Selected="no">
<Project Name="MyProject" ConfigName="x86-Debug"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="x86_64-Release" Selected="no">
<Project Name="MyProject" ConfigName="x86_64-Release"/>
</WorkspaceConfiguration>
<WorkspaceConfiguration Name="x86-Release" Selected="no">
<Project Name="MyProject" ConfigName="x86-Release"/>
</WorkspaceConfiguration>
</BuildMatrix>
</CodeLite_Workspace>
]]
end

View File

@@ -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.

View File

@@ -0,0 +1,84 @@
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.
C and C++ projects that include .d files will also support some of the API below. Any API tagged with (D/C/C++) works in D and C/C++ projects. Any API tagged with (C/C++) only works for .d files in C/C++ projects.
### APIs ###
* [flags](https://github.com/premake/premake-dlang/wiki/flags)
* AllInstantiate
* CodeCoverage
* Color
* Documentation
* GenerateHeader
* GenerateJSON
* GenerateMap
* IgnorePragma
* LowMem
* Main
* PerformSyntaxCheckOnly
* Profile
* ProfileGC
* Quiet
* RetainPaths
* ShowCommandLine
* ShowDependencies
* ShowGC
* ShowTLS
* StackFrame
* StackStomp
* SymbolsLikeC
* UnitTest
* UseLDC
* Verbose
* boundscheck ("type") [Off, SafeOnly, On]
* compilationmodel ("model") [ Project, Package, File ]
* checkaction
* computetargets
* [debugconstants](https://github.com/premake/premake-dlang/wiki/debugconstants)
* [debuglevel](https://github.com/premake/premake-dlang/wiki/debuglevel)
* dependenciesfile ("filename")
* deprecatedfeatures ("feature") [ Error, Info, Allow ]
* [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)
* importdirs { "paths" }
* [inlining](https://github.com/premake/premake-core/wiki/inlining)
* jsonfile ("filename")
* importdirs
* [optimize](https://github.com/premake/premake-core/wiki/optimize)
* preview
* revert
* runtime ("type") [ Debug, Release ]
* staticruntime ("state") [ on, off ]
* stringimportdirs { "paths" }
* transition
* [versionconstants](https://github.com/premake/premake-dlang/wiki/versionconstants)
* [versionlevel](https://github.com/premake/premake-dlang/wiki/versionlevel)
### 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" }
```

View File

@@ -0,0 +1,10 @@
return {
"_preload.lua",
"d.lua",
"actions/gmake.lua",
"actions/vcxproj.lua",
"actions/visuald.lua",
"tools/dmd.lua",
"tools/gdc.lua",
"tools/ldc.lua",
}

View File

@@ -0,0 +1,272 @@
--
-- 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",
"Color",
"Documentation",
"GenerateHeader",
"GenerateJSON",
"GenerateMap",
"LowMem",
"Profile",
"Quiet",
"RetainPaths",
"SymbolsLikeC",
"UnitTest",
-- These are used by C++/D mixed $todo move them somewhere else? "flags2" "Dflags"?
-- [Code Generation Flags]
"UseLDC",
"ProfileGC",
"StackFrame",
"StackStomp",
"AllInstantiate",
"BetterC",
"Main",
"PerformSyntaxCheckOnly",
-- [Messages Flags]
"ShowCommandLine",
"Verbose",
"ShowTLS",
"ShowGC",
"IgnorePragma",
"ShowDependencies",
})
api.addAllowed("toolset", {
"dmd",
"gdc",
"ldc",
})
--
-- Register some D specific properties
--
api.register {
name = "boundscheck",
scope = "config",
kind = "string",
allowed = {
"Default",
"Off",
"On",
"SafeOnly",
},
}
api.register {
name = "compilationmodel",
scope = "config",
kind = "string",
allowed = {
"Default",
"File",
"Package", -- TODO: this doesn't work with gmake!!
"Project",
},
}
api.register {
name = "checkaction",
scope = "config",
kind = "string",
allowed = {
"Default",
"D",
"C",
"Halt",
"Context",
},
}
api.register {
name = "computetargets",
scope = "config",
kind = "list:string",
}
-- api.register {
-- name = "debugcode",
-- scope = "config",
-- kind = "string",
-- }
api.register {
name = "debugconstants",
scope = "config",
kind = "list:string",
tokens = true,
}
api.register {
name = "debuglevel",
scope = "config",
kind = "integer",
}
api.register {
name = "dependenciesfile",
scope = "config",
kind = "path",
tokens = true,
}
api.register {
name = "deprecatedfeatures",
scope = "config",
kind = "string",
allowed = {
"Default",
"Allow",
"Warn",
"Error",
},
}
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,
}
api.register {
name = "jsonfile",
scope = "config",
kind = "path",
tokens = true,
}
api.register {
name = "importdirs",
scope = "config",
kind = "list:path",
tokens = true,
}
api.register {
name = "preview",
scope = "config",
kind = "list:string",
allowed = {
"dip25",
"dip1000",
"dip1008",
"fieldwise",
"markdown",
"fixAliasThis",
"intpromote",
"dtorfields",
},
}
api.register {
name = "revert",
scope = "config",
kind = "list:string",
allowed = {
"dip25",
"import",
},
}
api.register {
name = "stringimportdirs",
scope = "config",
kind = "list:path",
tokens = true,
}
api.register {
name = "transition",
scope = "config",
kind = "list:string",
allowed = {
"field",
"checkimports",
"complex",
"tls",
"vmarkdown",
},
}
api.register {
name = "versionconstants",
scope = "config",
kind = "list:string",
tokens = true,
}
api.register {
name = "versionlevel",
scope = "config",
kind = "integer",
}
--
-- Provide information for the help output
--
newoption
{
category = "compilers",
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 or cfg.language == "C" or cfg.language == "C++")
end

View File

@@ -0,0 +1,395 @@
--
-- 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
require ("gmake")
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.compilationmodel == "File" 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.compilationmodel == "File" 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.compilationmodel == "File" 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
_p('\t$(SILENT) $(DC) $(ALL_DFLAGS) $(OUTPUTFLAG) -c $<')
else
oldfn(prj, node)
end
end)
--
-- Let make know it can compile D source files
--
p.override(make, "fileType", function(oldfn, node)
if path.isdfile(node.abspath) then
return "objects"
else
return oldfn(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.stringImports,
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 = m.make.getToolset(cfg)
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.getToolset(cfg)
local toolset, err = p.api.checkValue(p.fields.toolset, _OPTIONS.dc or cfg.toolset or "dmd")
if err then
error { msg=err }
end
return p.tools[toolset]
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.compilationmodel == "File" 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 imports = p.esc(toolset.getimportdirs(cfg, cfg.importdirs))
_p(' IMPORTS +=%s', make.list(imports))
end
function m.make.stringImports(cfg, toolset)
local stringImports = p.esc(toolset.getstringimportdirs(cfg, cfg.stringimportdirs))
_p(' STRINGIMPORTS +=%s', make.list(stringImports))
end
function m.make.dFlags(cfg, toolset)
_p(' ALL_DFLAGS += $(DFLAGS)%s $(VERSIONS) $(DEBUG) $(IMPORTS) $(STRINGIMPORTS) $(ARCH)', make.list(table.join(toolset.getdflags(cfg), cfg.buildoptions)))
end
function m.make.linkCmd(cfg, toolset)
if cfg.compilationmodel == "File" then
_p(' LINKCMD = $(DC) ' .. toolset.gettarget("$(TARGET)") .. ' $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)')
-- local cc = iif(p.languages.isc(cfg.language), "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.compilationmodel == "File" 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

View File

@@ -0,0 +1,531 @@
--
-- d/actions/vcxproj.lua
-- Generate a VisualD .visualdproj project.
-- Copyright (c) 2012-2015 Manu Evans and the Premake project
--
local p = premake
require ("vstudio")
p.modules.d.vc2010 = {}
local vc2010 = p.vstudio.vc2010
local m = p.modules.d.vc2010
m.elements = {}
local vstudio = p.vstudio
local vc2010 = p.vstudio.vc2010
local config = p.config
--
-- Patch DCompiler into the configuration properties
--
p.override(vc2010.elements, "configurationProperties", function(oldfn, cfg)
local items = oldfn(cfg)
if cfg.kind ~= p.UTILITY then
table.insert(items, m.dCompiler)
end
return items
end)
function m.dCompiler(cfg)
local dc = nil
-- TODO: chech for explicit DMD or LDC request?
if _OPTIONS.dc then
local dcMap = {
["dmd"] = "DMD",
["ldc"] = "LDC",
}
dc = dcMap[_OPTIONS.dc]
end
if cfg.flags.UseLDC then
dc = "LDC"
end
-- TODO: dunno how to use `toolset`, since it's also used by the C++ compiler :/
-- local tool, version = p.config.toolset(cfg)
-- if not version then
-- local value = p.action.current().toolset
-- tool, version = p.tools.canonical(value)
-- end
if dc then
if cfg.kind == p.NONE or cfg.kind == p.MAKEFILE then
if p.config.hasFile(cfg, path.isdfile) or _ACTION >= "vs2015" then
vc2010.element("DCompiler", nil, dc)
end
else
vc2010.element("DCompiler", nil, dc)
end
end
end
--
-- Patch the dCompile step into the project items
--
p.override(vc2010.elements, "itemDefinitionGroup", function(oldfn, cfg)
local items = oldfn(cfg)
if cfg.kind ~= p.UTILITY then
table.insertafter(items, vc2010.clCompile, m.dCompile)
end
return items
end)
--
-- Write the <DCompile> settings block.
--
m.elements.dCompile = function(cfg)
return {
m.dOptimization,
m.dImportPaths,
m.dStringImportPaths,
m.dVersionConstants,
m.dDebugConstants,
m.dCompilationModel,
m.dPreserveSourcePath,
m.dRuntime,
m.dCodeGeneration,
m.dLanguage,
m.dMessages,
m.dDocumentation,
m.dAdditionalCompileOptions,
}
end
function m.dCompile(cfg)
if config.hasFile(cfg, path.isdfile) then
p.push('<DCompile>')
p.callArray(m.elements.dCompile, cfg)
p.pop('</DCompile>')
end
end
---
-- DCompile group
---
vc2010.categories.DCompile = {
name = "DCompile",
extensions = { ".d" },
priority = 3,
emitFiles = function(prj, group)
local fileCfgFunc = function(fcfg, condition)
if fcfg then
return {
vc2010.excludedFromBuild,
m.dOptimization,
m.dImportPaths,
m.dStringImportPaths,
m.dVersionConstants,
m.dDebugConstants,
m.dCompilationModel,
m.dPreserveSourcePath,
m.dRuntime,
m.dCodeGeneration,
m.dLanguage,
m.dMessages,
m.dDocumentation,
m.dAdditionalCompileOptions,
}
else
return {
vc2010.excludedFromBuild
}
end
end
vc2010.emitFiles(prj, group, "DCompile", {m.generatedFile}, fileCfgFunc)
end,
emitFilter = function(prj, group)
vc2010.filterGroup(prj, group, "DCompile")
end
}
function m.dOptimization(cfg, condition)
local map = { Off="false", On="true", Debug="false", Full="true", Size="true", Speed="true" }
if cfg.optimize then
vc2010.element('Optimizer', condition, map[cfg.optimize] or "false")
end
end
function m.dImportPaths(cfg, condition)
if cfg.importdirs and #cfg.importdirs > 0 then
local dirs = vstudio.path(cfg, cfg.importdirs)
if #dirs > 0 then
vc2010.element("ImportPaths", condition, "%s;%%(ImportPaths)", table.concat(dirs, ";"))
end
end
end
function m.dStringImportPaths(cfg, condition)
if cfg.stringimportdirs and #cfg.stringimportdirs > 0 then
local dirs = vstudio.path(cfg, cfg.stringimportdirs)
if #dirs > 0 then
vc2010.element("StringImportPaths", condition, "%s;%%(StringImportPaths)", table.concat(dirs, ";"))
end
end
end
function m.dVersionConstants(cfg, condition)
if cfg.versionconstants and #cfg.versionconstants > 0 then
local versionconstants = table.concat(cfg.versionconstants, ";")
vc2010.element("VersionIdentifiers", condition, versionconstants)
end
end
function m.dDebugConstants(cfg, condition)
if cfg.debugconstants and #cfg.debugconstants > 0 then
local debugconstants = table.concat(cfg.debugconstants, ";")
vc2010.element("DebugIdentifiers", condition, debugconstants)
end
end
function m.dCompilationModel(cfg, condition)
if cfg.compilationmodel and cfg.compilationmodel ~= "Default" then
vc2010.element("CompilationModel", condition, cfg.compilationmodel)
end
end
function m.dPreserveSourcePath(cfg, condition)
if cfg.flags.RetainPaths then
vc2010.element("PreserveSourcePath", condition, "true")
end
end
function m.dRuntime(cfg, condition)
if cfg.flags.OmitDefaultLibrary then
vc2010.element("CRuntimeLibrary", condition, "None")
else
local releaseruntime = not config.isDebugBuild(cfg)
local staticruntime = true
if cfg.staticruntime == "Off" then
staticruntime = false
end
if cfg.runtime == "Debug" then
releaseruntime = false
elseif cfg.runtime == "Release" then
releaseruntime = true
end
if (cfg.staticruntime and cfg.staticruntime ~= "Default") or (cfg.runtime and cfg.runtime ~= "Default") then
if staticruntime == true and releaseruntime == true then
vc2010.element("CRuntimeLibrary", condition, "MultiThreaded")
elseif staticruntime == true and releaseruntime == false then
vc2010.element("CRuntimeLibrary", condition, "MultiThreadedDebug")
elseif staticruntime == false and releaseruntime == true then
vc2010.element("CRuntimeLibrary", condition, "MultiThreadedDll")
elseif staticruntime == false and releaseruntime == false then
vc2010.element("CRuntimeLibrary", condition, "MultiThreadedDebugDll")
end
end
end
end
function m.dCodeGeneration(cfg, condition)
if cfg.buildtarget then
local ObjectFileName = ""
if cfg.buildtarget.basename then
if cfg.buildtarget.prefix then
ObjectFileName = cfg.buildtarget.prefix
end
ObjectFileName = ObjectFileName .. cfg.buildtarget.basename .. ".obj"
end
if cfg.buildtarget.directory then
local outdir = vstudio.path(cfg, cfg.buildtarget.directory)
ObjectFileName = path.join(outdir, ObjectFileName)
end
vc2010.element("ObjectFileName", condition, ObjectFileName)
end
if cfg.flags.Profile then
vc2010.element("Profile", condition, "true")
end
if cfg.flags.ProfileGC then
vc2010.element("ProfileGC", condition, "true")
end
if cfg.flags.CodeCoverage then
vc2010.element("Coverage", condition, "true")
end
if cfg.flags.UnitTest then
vc2010.element("Unittest", condition, "true")
end
if cfg.inlining and cfg.inlining ~= "Default" then
local types = {
Disabled = "false",
Explicit = "true",
Auto = "true",
}
vc2010.element("Inliner", condition, types[cfg.inlining])
end
if cfg.flags.StackFrame then
vc2010.element("StackFrame", condition, "true")
end
if cfg.flags.StackStomp then
vc2010.element("StackStomp", condition, "true")
end
if cfg.flags.AllInstantiate then
vc2010.element("AllInst", condition, "true")
end
if cfg.flags.Main then
vc2010.element("Main", condition, "true")
end
if _OPTIONS.dc ~= "ldc" and not cfg.flags.UseLDC then
if cfg.vectorextensions then
local vextMap = {
AVX = "avx",
AVX2 = "avx2",
}
if vextMap[cfg.vectorextensions] ~= nil then
vc2010.element("CPUArchitecture", condition, vextMap[cfg.vectorextensions])
end
end
end
-- if cfg.debugcode then
-- local types = {
-- DebugFull = "Debug",
-- DebugLight = "Default",
-- Release = "Release",
-- }
-- vc2010.element("DebugCode", condition, types[cfg.debugcode])
-- end
-- TODO: proper option for this? should support unspecified...
if config.isDebugBuild(cfg) then
vc2010.element("DebugCode", condition, "Debug")
else
vc2010.element("DebugCode", condition, "Release")
end
if cfg.symbols then
if cfg.symbols == p.Off then
vc2010.element("DebugInfo", condition, "None")
elseif cfg.symbols ~= "Default" then
vc2010.element("DebugInfo", condition, iif(cfg.flags.SymbolsLikeC, "VS", "Mago"))
end
end
if cfg.boundscheck and cfg.boundscheck ~= "Default" then
local types = {
Off = "Off",
SafeOnly = "SafeOnly",
On = "On",
}
vc2010.element("BoundsCheck", condition, types[cfg.boundscheck])
end
if cfg.flags.PerformSyntaxCheckOnly then
vc2010.element("PerformSyntaxCheckOnly", condition, "true")
end
end
function m.dLanguage(cfg, condition)
if cfg.flags.BetterC then
vc2010.element("BetterC", condition, "true")
end
if #cfg.preview > 0 then
for _, opt in ipairs(cfg.preview) do
if opt == "dip25" then
vc2010.element("DIP25", condition, "true")
elseif opt == "dip1000" then
vc2010.element("DIP1000", condition, "true")
elseif opt == "dip1008" then
vc2010.element("DIP1008", condition, "true")
elseif opt == "fieldwise" then
vc2010.element("PreviewFieldwise", condition, "true")
elseif opt == "dtorfields" then
vc2010.element("PreviewDtorFields", condition, "true")
elseif opt == "intpromote" then
vc2010.element("PreviewIntPromote", condition, "true")
elseif opt == "fixAliasThis" then
vc2010.element("PreviewFixAliasThis", condition, "true")
end
end
end
if #cfg.revert > 0 then
for _, opt in ipairs(cfg.revert) do
if opt == "import" then
vc2010.element("RevertImport", condition, "true")
end
end
end
end
function m.dMessages(cfg, condition)
if cfg.warnings == p.OFF then
vc2010.element("Warnings", condition, "None")
elseif cfg.warnings and cfg.warnings ~= "Default" then
vc2010.element("Warnings", condition, iif(cfg.flags.FatalCompileWarnings, "Error", "Info"))
end
if cfg.deprecatedfeatures and cfg.deprecatedfeatures ~= "Default" then
local types = {
Error = "Error",
Warn = "Info",
Allow = "Allow",
}
vc2010.element("Deprecations", condition, types[cfg.deprecatedfeatures])
end
if cfg.flags.ShowCommandLine then
vc2010.element("ShowCommandLine", condition, "true")
end
if cfg.flags.Verbose then
vc2010.element("Verbose", condition, "true")
end
if cfg.flags.ShowTLS then
vc2010.element("ShowTLS", condition, "true")
end
if cfg.flags.ShowGC then
vc2010.element("ShowGC", condition, "true")
end
if cfg.flags.IgnorePragma then
vc2010.element("IgnorePragma", condition, "true")
end
if cfg.flags.ShowDependencies then
vc2010.element("ShowDependencies", condition, "true")
end
if #cfg.transition > 0 then
for _, opt in ipairs(cfg.transition) do
if opt == "field" then
vc2010.element("TransitionField", condition, "true")
elseif opt == "checkimports" then
vc2010.element("TransitionCheckImports", condition, "true")
elseif opt == "complex" then
vc2010.element("TransitionComplex", condition, "true")
end
end
end
end
function m.dDocumentation(cfg, condition)
if cfg.docdir then
vc2010.element("DocDir", condition, cfg.docdir)
end
if cfg.docname then
vc2010.element("DocFile", condition, cfg.docname)
end
if #cfg.preview > 0 then
for _, opt in ipairs(cfg.preview) do
if opt == "markdown" then
vc2010.element("PreviewMarkdown", condition, "true")
end
end
end
if #cfg.transition > 0 then
for _, opt in ipairs(cfg.transition) do
if opt == "vmarkdown" then
vc2010.element("TransitionVMarkdown", condition, "true")
end
end
end
if cfg.dependenciesfile then
vc2010.element("DepFile", condition, cfg.dependenciesfile)
end
if cfg.headerdir then
vc2010.element("HeaderDir", condition, cfg.headerdir)
end
if cfg.headername then
vc2010.element("HeaderFile", condition, cfg.headername)
end
if cfg.jsonfile then
vc2010.element("JSONFile", condition, cfg.jsonfile)
end
end
function m.dAdditionalCompileOptions(cfg, condition)
local opts = cfg.buildoptions
if cfg.flags.LowMem then
table.insert(opts, "-lowmem")
end
if cfg.cppdialect and cfg.cppdialect ~= "Default" then
local cppMap = {
["C++latest"] = "c++20",
["C++98"] = "c++98",
["C++0x"] = "c++11",
["C++11"] = "c++11",
["C++1y"] = "c++14",
["C++14"] = "c++14",
["C++1z"] = "c++17",
["C++17"] = "c++17",
["C++2a"] = "c++20",
["C++20"] = "c++20",
["gnu++98"] = "c++98",
["gnu++0x"] = "c++11",
["gnu++11"] = "c++11",
["gnu++1y"] = "c++14",
["gnu++14"] = "c++14",
["gnu++1z"] = "c++17",
["gnu++17"] = "c++17",
["gnu++2a"] = "c++20",
["gnu++20"] = "c++20",
}
if cppMap[cfg.cppdialect] ~= nil then
table.insert(opts, "-extern-std=" .. cppMap[cfg.cppdialect])
end
end
-- TODO: better way to check toolset?
if _OPTIONS.dc == "ldc" or cfg.flags.UseLDC then
if cfg.vectorextensions then
local vextMap = {
AVX = "avx",
AVX2 = "avx2",
SSE = "sse",
SSE2 = "sse2",
SSE3 = "sse3",
SSSE3 = "ssse3",
["SSE4.1"] = "sse4.1",
["SSE4.2"] = "sse4.2",
}
if vextMap[cfg.vectorextensions] ~= nil then
table.insert(opts, "-mattr=+" .. vextMap[cfg.vectorextensions])
end
end
if #cfg.isaextensions > 0 then
local isaMap = {
MOVBE = "movbe",
POPCNT = "popcnt",
PCLMUL = "pclmul",
LZCNT = "lzcnt",
BMI = "bmi",
BMI2 = "bmi2",
F16C = "f16c",
AES = "aes",
FMA = "fma",
FMA4 = "fma4",
RDRND = "rdrnd",
}
for _, ext in ipairs(cfg.isaextensions) do
if isaMap[ext] ~= nil then
table.insert(opts, "-mattr=+" .. isaMap[ext])
end
end
end
if #cfg.computetargets > 0 then
table.insert(opts, "-mdcompute-targets=" .. table.concat(cfg.computetargets, ','))
end
end
if #opts > 0 then
opts = table.concat(opts, " ")
vc2010.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts)
end
end

View File

@@ -0,0 +1,364 @@
--
-- d/actions/visuald.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 = {}
require ("vstudio")
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", "vs2017", "vs2019" }) 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('</DProject>')
end
function m.visuald.header(prj)
-- for some reason Visual D projects don't seem to have an xml header
--_p('<?xml version="1.0" encoding="utf-8"?>')
_p('<DProject>')
end
function m.visuald.globals(prj)
_p(1,'<ProjectGuid>{%s}</ProjectGuid>', 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,'<Config name="%s" platform="%s">', prjPlatform, slnPlatform)
_p(2,'<obj>0</obj>')
_p(2,'<link>0</link>')
local isWindows = false
local isDebug = string.find(cfg.buildcfg, 'Debug') ~= nil
local isOptimised = config.isOptimizedBuild(cfg)
if cfg.kind == p.CONSOLEAPP then
_p(2,'<lib>0</lib>')
_p(2,'<subsystem>1</subsystem>')
elseif cfg.kind == p.STATICLIB then
_p(2,'<lib>1</lib>')
_p(2,'<subsystem>0</subsystem>')
elseif cfg.kind == p.SHAREDLIB then
_p(2,'<lib>2</lib>')
_p(2,'<subsystem>0</subsystem>') -- SHOULD THIS BE '2' (windows)??
else
_p(2,'<lib>0</lib>')
_p(2,'<subsystem>2</subsystem>')
isWindows = true
end
_p(2,'<multiobj>0</multiobj>')
_p(2,'<singleFileCompilation>0</singleFileCompilation>')
_p(2,'<oneobj>0</oneobj>')
_p(2,'<trace>%s</trace>', iif(cfg.flags.Profile, '1', '0'))
_p(2,'<quiet>%s</quiet>', iif(cfg.flags.Quiet, '1', '0'))
_p(2,'<verbose>%s</verbose>', iif(cfg.flags.Verbose, '1', '0'))
_p(2,'<vtls>0</vtls>')
_p(2,'<symdebug>%s</symdebug>', iif(cfg.symbols == p.ON or cfg.symbols == "FastLink" or cfg.symbols == "Full", iif(cfg.flags.SymbolsLikeC, '2', '1'), '0'))
_p(2,'<optimize>%s</optimize>', iif(isOptimised, '1', '0'))
_p(2,'<cpu>0</cpu>')
_p(2,'<isX86_64>%s</isX86_64>', iif(is64bit, '1', '0'))
_p(2,'<isLinux>0</isLinux>')
_p(2,'<isOSX>0</isOSX>')
_p(2,'<isWindows>%s</isWindows>', iif(isWindows, '1', '0'))
_p(2,'<isFreeBSD>0</isFreeBSD>')
_p(2,'<isSolaris>0</isSolaris>')
_p(2,'<scheduler>0</scheduler>')
_p(2,'<useDeprecated>%s</useDeprecated>', iif(cfg.deprecatedfeatures == "Allow", '1', '0'))
_p(2,'<errDeprecated>0</errDeprecated>')
_p(2,'<useAssert>0</useAssert>')
_p(2,'<useInvariants>0</useInvariants>')
_p(2,'<useIn>0</useIn>')
_p(2,'<useOut>0</useOut>')
_p(2,'<useArrayBounds>0</useArrayBounds>')
_p(2,'<noboundscheck>%s</noboundscheck>', iif(cfg.boundscheck == "Off", '1', '0'))
_p(2,'<useSwitchError>0</useSwitchError>')
_p(2,'<useUnitTests>%s</useUnitTests>', iif(cfg.flags.UnitTest, '1', '0'))
_p(2,'<useInline>%s</useInline>', iif(cfg.flags.Inline or isOptimised, '1', '0'))
_p(2,'<release>%s</release>', iif(cfg.flags.Release or not isDebug, '1', '0'))
_p(2,'<preservePaths>0</preservePaths>')
_p(2,'<warnings>%s</warnings>', iif(cfg.flags.FatalCompileWarnings, '1', '0'))
_p(2,'<infowarnings>%s</infowarnings>', iif(cfg.warnings and cfg.warnings ~= "Off", '1', '0'))
_p(2,'<checkProperty>0</checkProperty>')
_p(2,'<genStackFrame>0</genStackFrame>')
_p(2,'<pic>%s</pic>', iif(cfg.pic == "On", '1', '0'))
_p(2,'<cov>%s</cov>', iif(cfg.flags.CodeCoverage, '1', '0'))
_p(2,'<nofloat>%s</nofloat>', iif(cfg.floatingpoint and cfg.floatingpoint == "None", '1', '0'))
_p(2,'<Dversion>2</Dversion>')
_p(2,'<ignoreUnsupportedPragmas>0</ignoreUnsupportedPragmas>')
local compiler = { dmd="0", gdc="1", ldc="2" }
local compilerName, err = p.api.checkValue(p.fields.toolset, _OPTIONS.dc or cfg.toolset or "dmd")
if err then
error { msg=err }
end
m.visuald.element(2, "compiler", compiler[compilerName])
m.visuald.element(2, "otherDMD", '0')
m.visuald.element(2, "program", '$(DMDInstallDir)windows\\bin\\dmd.exe')
local impdirs
if #cfg.importdirs > 0 then
impdirs = vstudio.path(cfg, cfg.importdirs)
end
m.visuald.element(2, "imppath", impdirs)
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,'<dump_source>0</dump_source>')
_p(2,'<mapverbosity>0</mapverbosity>')
_p(2,'<createImplib>%s</createImplib>', iif(cfg.kind ~= p.SHAREDLIB or cfg.flags.NoImportLib, '0', '1'))
_p(2,'<defaultlibname />')
_p(2,'<debuglibname />')
_p(2,'<moduleDepsFile />')
_p(2,'<run>0</run>')
_p(2,'<runargs />')
-- _p(2,'<runCv2pdb>%s</runCv2pdb>', iif(cfg.symbols == p.ON, '1', '0'))
_p(2,'<runCv2pdb>1</runCv2pdb>') -- we will just leave this always enabled, since it's ignored if no debuginfo is written
_p(2,'<pathCv2pdb>$(VisualDInstallDir)cv2pdb\\cv2pdb.exe</pathCv2pdb>')
_p(2,'<cv2pdbPre2043>0</cv2pdbPre2043>')
_p(2,'<cv2pdbNoDemangle>0</cv2pdbNoDemangle>')
_p(2,'<cv2pdbEnumType>0</cv2pdbEnumType>')
_p(2,'<cv2pdbOptions />')
_p(2,'<objfiles />')
_p(2,'<linkswitches />')
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,'<deffile />')
_p(2,'<resfile />')
local target = config.gettargetinfo(cfg)
_p(2,'<exefile>$(OutDir)\\%s</exefile>', target.name)
_p(2,'<useStdLibPath>1</useStdLibPath>')
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,'<preBuildCommand>%s</preBuildCommand>',p.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n")))
else
_p(2,'<preBuildCommand />')
end
if #cfg.postbuildcommands > 0 then
_p(2,'<postBuildCommand>%s</postBuildCommand>',p.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n")))
else
_p(2,'<postBuildCommand />')
end
_p(2,'<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep;*.o</filesToClean>')
_p(1,'</Config>')
end
end
--
-- Write out the source file tree.
--
function m.visuald.files(prj)
_p(1,'<Folder name="%s">', 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, '<Folder name="%s">', node.name)
end,
onbranchexit = function(node, depth)
_p(depth, '</Folder>')
end,
-- source files are handled at the leaves
onleaf = function(node, depth)
_p(depth, '<File path="%s" />', path.translate(node.relpath))
-- _p(depth, '<File path="%s">', path.translate(node.relpath))
-- m.visuald.fileConfiguration(prj, node, depth + 1)
-- _p(depth, '</File>')
end
}, false, 2)
_p(1,'</Folder>')
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</%s>', name, value, name)
else
if select('#',...) == 0 then
value = p.esc(value)
end
_x(depth, string.format('<%s>%s</%s>', name, value, name), ...)
end
end
end

View File

@@ -0,0 +1,49 @@
--
-- 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 == p.D
end
--
-- Patch the path table to provide knowledge of D file extenstions
--
function path.isdfile(fname)
return path.hasextension(fname, { ".d" })
end
function path.isdheader(fname)
return path.hasextension(fname, { ".di" })
end
--
-- Patch actions
--
include( "tools/dmd.lua" )
include( "tools/gdc.lua" )
include( "tools/ldc.lua" )
include( "actions/gmake.lua" )
include( "actions/vcxproj.lua" )
include( "actions/visuald.lua" )
return m

View File

@@ -0,0 +1,9 @@
require ("d")
return {
"test_visualstudio.lua",
"test_gmake.lua",
"test_dmd.lua",
"test_gdc.lua",
"test_ldc.lua",
}

View File

@@ -0,0 +1,106 @@
---
-- 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 p = premake
local m = p.modules.d
local make = p.make
local project = p.project
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.escaper(make.esc)
wks = test.createWorkspace()
end
local function prepare_cfg(calls)
prj = p.workspace.getproject(wks, 1)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.dmd
p.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()
compilationmodel "File"
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()
importdirs { "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) $(STRINGIMPORTS) $(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()
compilationmodel "File"
prepare_cfg({ m.make.linkCmd })
test.capture [[
LINKCMD = $(DC) -of$(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)
]]
end

View File

@@ -0,0 +1,106 @@
---
-- 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 p = premake
local m = p.modules.d
local make = p.make
local project = p.project
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.escaper(make.esc)
wks = test.createWorkspace()
end
local function prepare_cfg(calls)
prj = p.workspace.getproject(wks, 1)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gdc
p.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()
compilationmodel "File"
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()
importdirs { "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) $(STRINGIMPORTS) $(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()
compilationmodel "File"
prepare_cfg({ m.make.linkCmd })
test.capture [[
LINKCMD = $(DC) -o $(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)
]]
end

View File

@@ -0,0 +1,222 @@
---
-- 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 p = premake
local m = p.modules.d
local make = p.make
local project = p.project
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.escaper(make.esc)
wks = test.createWorkspace()
end
local function prepare()
prj = p.workspace.getproject(wks, 1)
end
local function prepare_cfg(calls)
prj = p.workspace.getproject(wks, 1)
local cfg = test.getconfig(prj, "Debug")
local toolset = m.make.getToolset(cfg) or p.tools.dmd
p.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()
compilationmodel "File"
prepare()
m.make.targetRules(prj)
test.capture [[
$(TARGET): $(OBJECTS) $(LDDEPS)
@echo Linking MyProject
$(SILENT) $(LINKCMD)
$(POSTBUILDCMDS)
]]
end
function suite.make_targetRules_mixedCompilation()
configuration { "Release" }
compilationmodel "File"
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" }
compilationmodel "File"
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" }
compilationmodel "File"
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" }
compilationmodel "File"
prepare()
m.make.objects(prj)
test.capture [[
OBJECTS := \
$(OBJDIR)/blah.o \
]]
end
function suite.make_objects_mixedCompilation()
files { "blah.d" }
configuration { "Release" }
compilationmodel "File"
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()
compilationmodel "File"
prepare_cfg({ m.make.allRules })
test.capture [[
all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET)
@:
]]
end
function suite.make_dTools_dmd()
toolset "dmd"
prepare_cfg({ m.make.dTools })
test.capture [[
DC = dmd
]]
end
function suite.make_dTools_gdc()
toolset "gdc"
prepare_cfg({ m.make.dTools })
test.capture [[
DC = gdc
]]
end
function suite.make_dTools_ldc()
toolset "ldc"
prepare_cfg({ m.make.dTools })
test.capture [[
DC = ldc2
]]
end

View File

@@ -0,0 +1,106 @@
---
-- 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 p = premake
local m = p.modules.d
local make = p.make
local project = p.project
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.escaper(make.esc)
wks = test.createWorkspace()
end
local function prepare_cfg(calls)
prj = p.workspace.getproject(wks, 1)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.ldc
p.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()
compilationmodel "File"
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()
importdirs { "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) $(STRINGIMPORTS) $(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()
compilationmodel "File"
prepare_cfg({ m.make.linkCmd })
test.capture [[
LINKCMD = $(DC) -of=$(TARGET) $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)
]]
end

View File

@@ -0,0 +1,75 @@
---
-- 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 p = premake
local m = p.modules.d
---------------------------------------------------------------------------
-- Setup/Teardown
---------------------------------------------------------------------------
local wks, prj, cfg
function suite.setup()
p.action.set("vs2010")
-- p.escaper(p.vstudio.vs2005.esc)
p.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"
p.vstudio.sln2005.reorderProjects(wks)
p.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 [[
<DProject>
]]
end
function suite.OnProject_globals()
prepare()
m.visuald.globals(prj)
test.capture [[
<ProjectGuid>{42B5DBC6-AE1F-903D-F75D-41E363076E92}</ProjectGuid>
]]
end
-- TODO: break up the project gen and make lots more tests...

View File

@@ -0,0 +1,486 @@
--
-- d/tools/dmd.lua
-- Provides dmd-specific configuration strings.
-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project
--
local tdmd = {}
local p = premake
local project = p.project
local config = p.config
local d = p.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 == p.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 == p.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, p.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 ~= p.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")
p.tools.dmd = tdmd.optlink
else
p.tools.dmd = tdmd.gcc
end
local dmd = p.tools.dmd
--
-- Returns list of D compiler flags for a configuration.
--
dmd.dflags = {
architecture = {
x86 = "-m32mscoff",
x86_64 = "-m64",
},
flags = {
OmitDefaultLibrary = "-mscrtlib=",
CodeCoverage = "-cov",
Color = "-color",
Documentation = "-D",
FatalWarnings = "-w",
GenerateHeader = "-H",
GenerateJSON = "-X",
GenerateMap = "-map",
LowMem = "-lowmem",
Profile = "-profile",
Quiet = "-quiet",
RetainPaths = "-op",
SymbolsLikeC = "-gc",
UnitTest = "-unittest",
Verbose = "-v",
ProfileGC = "-profile=gc",
StackFrame = "-gs",
StackStomp = "-gx",
AllInstantiate = "-allinst",
BetterC = "-betterC",
Main = "-main",
PerformSyntaxCheckOnly = "-o-",
ShowTLS = "-vtls",
ShowGC = "-vgc",
IgnorePragma = "-ignore",
ShowDependencies = "-deps",
},
boundscheck = {
Off = "-boundscheck=off",
On = "-boundscheck=on",
SafeOnly = "-boundscheck=safeonly",
},
checkaction = {
D = "-checkaction=D",
C = "-checkaction=C",
Halt = "-checkaction=halt",
Context = "-checkaction=context",
},
cppdialect = {
["C++latest"] = "-extern-std=c++20", -- TODO: keep this up to date >_<
["C++98"] = "-extern-std=c++98",
["C++0x"] = "-extern-std=c++11",
["C++11"] = "-extern-std=c++11",
["C++1y"] = "-extern-std=c++14",
["C++14"] = "-extern-std=c++14",
["C++1z"] = "-extern-std=c++17",
["C++17"] = "-extern-std=c++17",
["C++2a"] = "-extern-std=c++20",
["C++20"] = "-extern-std=c++20",
["gnu++98"] = "-extern-std=c++98",
["gnu++0x"] = "-extern-std=c++11",
["gnu++11"] = "-extern-std=c++11",
["gnu++1y"] = "-extern-std=c++14",
["gnu++14"] = "-extern-std=c++14",
["gnu++1z"] = "-extern-std=c++17",
["gnu++17"] = "-extern-std=c++17",
["gnu++2a"] = "-extern-std=c++20",
["gnu++20"] = "-extern-std=c++20",
},
deprecatedfeatures = {
Allow = "-d",
Warn = "-dw",
Error = "-de",
},
floatingpoint = {
None = "-nofloat",
},
optimize = {
On = "-O -inline",
Full = "-O -inline",
Size = "-O -inline",
Speed = "-O -inline",
},
pic = {
On = "-fPIC",
},
symbols = {
On = "-g",
FastLink = "-g",
Full = "-g",
},
vectorextensions = {
AVX = "-mcpu=avx",
AVX2 = "-mcpu=avx2",
},
warnings = {
Default = "-wi",
High = "-wi",
Extra = "-wi",
Everything = "-wi",
},
}
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
if not cfg.flags.OmitDefaultLibrary then
local releaseruntime = not config.isDebugBuild(cfg)
local staticruntime = true
if cfg.staticruntime == "Off" then
staticruntime = false
end
if cfg.runtime == "Debug" then
releaseruntime = false
elseif cfg.runtime == "Release" then
releaseruntime = true
end
if (cfg.staticruntime and cfg.staticruntime ~= "Default") or (cfg.runtime and cfg.runtime ~= "Default") then
if staticruntime == true and releaseruntime == true then
table.insert(flags, "-mscrtlib=libcmt")
elseif staticruntime == true and releaseruntime == false then
table.insert(flags, "-mscrtlib=libcmtd")
elseif staticruntime == false and releaseruntime == true then
table.insert(flags, "-mscrtlib=msvcrt")
elseif staticruntime == false and releaseruntime == false then
table.insert(flags, "-mscrtlib=msvcrtd")
end
end
end
if cfg.flags.Documentation then
if cfg.docname then
table.insert(flags, "-Df" .. p.quoted(cfg.docname))
end
if cfg.docdir then
table.insert(flags, "-Dd" .. p.quoted(cfg.docdir))
end
end
if cfg.flags.GenerateHeader then
if cfg.headername then
table.insert(flags, "-Hf" .. p.quoted(cfg.headername))
end
if cfg.headerdir then
table.insert(flags, "-Hd" .. p.quoted(cfg.headerdir))
end
end
if #cfg.preview > 0 then
for _, opt in ipairs(cfg.preview) do
table.insert(flags, "-preview=" .. opt)
end
end
if #cfg.revert > 0 then
for _, opt in ipairs(cfg.revert) do
table.insert(flags, "-revert=" .. opt)
end
end
if #cfg.transition > 0 then
for _, opt in ipairs(cfg.transition) do
table.insert(flags, "-transition=" .. opt)
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' .. p.quoted(dir))
end
return result
end
--
-- Decorate string import file search paths for the DMD command line.
--
function dmd.getstringimportdirs(cfg, dirs)
local result = {}
for _, dir in ipairs(dirs) do
dir = project.getrelative(cfg.project, dir)
table.insert(result, '-J' .. p.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

View File

@@ -0,0 +1,328 @@
--
-- d/tools/gdc.lua
-- Provides GDC-specific configuration strings.
-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project
--
local p = premake
p.tools.gdc = { }
local gdc = p.tools.gdc
local project = p.project
local config = p.config
local d = p.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 = {
Documentation = "-fdoc",
FatalWarnings = "-Werror",
GenerateHeader = "-fintfc",
GenerateJSON = "-fX",
-- Release = "-frelease",
RetainPaths = "-op",
SymbolsLikeC = "-fdebug-c",
UnitTest = "-funittest",
Verbose = "-fd-verbose",
-- THESE ARE THE DMD ARGS...
-- ProfileGC = "-profile=gc",
-- StackFrame = "-gs",
-- StackStomp = "-gx",
-- AllInstantiate = "-allinst",
-- BetterC = "-betterC",
-- Main = "-main",
-- PerformSyntaxCheckOnly = "-o-",
ShowTLS = "-fd-vtls",
-- ShowGC = "-vgc",
-- IgnorePragma = "-ignore",
ShowDependencies = "-fdeps",
},
boundscheck = {
Off = "-fno-bounds-check",
-- On = "-boundscheck=on",
-- SafeOnly = "-boundscheck=safeonly",
},
deprecatedfeatures = {
Allow = "-fdeprecated",
-- Warn = "-dw",
-- Error = "-de",
},
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 = {
-- Default = "-w", -- TODO: check this...
High = "-Wall",
Extra = "-Wall -Wextra",
Everything = "-Weverything",
},
symbols = {
On = "-g",
FastLink = "-g",
Full = "-g -gf",
}
}
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
if cfg.flags.Documentation then
if cfg.docname then
table.insert(flags, "-fdoc-file=" .. p.quoted(cfg.docname))
end
if cfg.docdir then
table.insert(flags, "-fdoc-dir=" .. p.quoted(cfg.docdir))
end
end
if cfg.flags.GenerateHeader then
if cfg.headername then
table.insert(flags, "-fintfc-file=" .. p.quoted(cfg.headername))
end
if cfg.headerdir then
table.insert(flags, "-fintfc-dir=" .. p.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' .. p.quoted(dir))
end
return result
end
--
-- Decorate import file search paths for the DMD command line.
--
function gdc.getstringimportdirs(cfg, dirs)
local result = {}
for _, dir in ipairs(dirs) do
dir = project.getrelative(cfg.project, dir)
table.insert(result, '-J' .. p.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 == p.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 == p.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 == p.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

View File

@@ -0,0 +1,419 @@
--
-- d/tools/ldc.lua
-- Provides LDC-specific configuration strings.
-- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project
--
local p = premake
p.tools.ldc = { }
local ldc = p.tools.ldc
local project = p.project
local config = p.config
local d = p.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",
ARM64 = "-march=aarch64",
-- ppc = "-march=ppc32",
-- ppc64 = "-march=ppc64",
-- spu = "-march=cellspu",
-- mips = "-march=mips", -- -march=mipsel?
},
flags = {
OmitDefaultLibrary = "-mscrtlib=",
CodeCoverage = "-cov",
Color = "-enable-color",
Documentation = "-D",
FatalWarnings = "-w", -- Use LLVM flag? : "-fatal-assembler-warnings",
GenerateHeader = "-H",
GenerateJSON = "-X",
LowMem = "-lowmem",
RetainPaths = "-op",
SymbolsLikeC = "-gc",
UnitTest = "-unittest",
Verbose = "-v",
AllInstantiate = "-allinst",
BetterC = "-betterC",
Main = "-main",
PerformSyntaxCheckOnly = "-o-",
ShowGC = "-vgc",
IgnorePragma = "-ignore",
},
boundscheck = {
Off = "-boundscheck=off",
On = "-boundscheck=on",
SafeOnly = "-boundscheck=safeonly",
},
checkaction = {
D = "-checkaction=D",
C = "-checkaction=C",
Halt = "-checkaction=halt",
Context = "-checkaction=context",
},
cppdialect = {
["C++latest"] = "-extern-std=c++17", -- TODO: keep this up to date >_<
["C++98"] = "-extern-std=c++98",
["C++0x"] = "-extern-std=c++11",
["C++11"] = "-extern-std=c++11",
["C++1y"] = "-extern-std=c++14",
["C++14"] = "-extern-std=c++14",
["C++1z"] = "-extern-std=c++17",
["C++17"] = "-extern-std=c++17",
["C++2a"] = "-extern-std=c++20",
["C++20"] = "-extern-std=c++20",
["gnu++98"] = "-extern-std=c++98",
["gnu++0x"] = "-extern-std=c++11",
["gnu++11"] = "-extern-std=c++11",
["gnu++1y"] = "-extern-std=c++14",
["gnu++14"] = "-extern-std=c++14",
["gnu++1z"] = "-extern-std=c++17",
["gnu++17"] = "-extern-std=c++17",
["gnu++2a"] = "-extern-std=c++20",
["gnu++20"] = "-extern-std=c++20",
},
deprecatedfeatures = {
Allow = "-d",
Warn = "-dw",
Error = "-de",
},
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",
AVX2 = "-mattr=+avx2",
SSE = "-mattr=+sse",
SSE2 = "-mattr=+sse2",
SSE3 = "-mattr=+sse3",
SSSE3 = "-mattr=+ssse3",
["SSE4.1"] = "-mattr=+sse4.1",
["SSE4.2"] = "-mattr=+sse4.2",
},
warnings = {
Default = "-wi",
High = "-wi",
Extra = "-wi", -- TODO: is there a way to get extra warnings?
Everything = "-wi",
},
symbols = {
On = "-g",
FastLink = "-g",
Full = "-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
if not cfg.flags.OmitDefaultLibrary then
local releaseruntime = not config.isDebugBuild(cfg)
local staticruntime = true
if cfg.staticruntime == "Off" then
staticruntime = false
end
if cfg.runtime == "Debug" then
releaseruntime = false
elseif cfg.runtime == "Release" then
releaseruntime = true
end
if (cfg.staticruntime and cfg.staticruntime ~= "Default") or (cfg.runtime and cfg.runtime ~= "Default") then
if staticruntime == true and releaseruntime == true then
table.insert(flags, "-mscrtlib=libcmt")
elseif staticruntime == true and releaseruntime == false then
table.insert(flags, "-mscrtlib=libcmtd")
elseif staticruntime == false and releaseruntime == true then
table.insert(flags, "-mscrtlib=msvcrt")
elseif staticruntime == false and releaseruntime == false then
table.insert(flags, "-mscrtlib=msvcrtd")
end
end
end
if cfg.flags.Documentation then
if cfg.docname then
table.insert(flags, "-Df=" .. p.quoted(cfg.docname))
end
if cfg.docdir then
table.insert(flags, "-Dd=" .. p.quoted(cfg.docdir))
end
end
if cfg.flags.GenerateHeader then
if cfg.headername then
table.insert(flags, "-Hf=" .. p.quoted(cfg.headername))
end
if cfg.headerdir then
table.insert(flags, "-Hd=" .. p.quoted(cfg.headerdir))
end
end
if #cfg.computetargets > 0 then
table.insert(flags, "-mdcompute-targets=" .. table.concat(cfg.computetargets, ','))
end
if #cfg.isaextensions > 0 then
local isaMap = {
MOVBE = "movbe",
POPCNT = "popcnt",
PCLMUL = "pclmul",
LZCNT = "lzcnt",
BMI = "bmi",
BMI2 = "bmi2",
F16C = "f16c",
AES = "aes",
FMA = "fma",
FMA4 = "fma4",
RDRND = "rdrnd",
}
for _, ext in ipairs(cfg.transition) do
if isaMap[ext] ~= nil then
table.insert(flags, "-mattr=+" .. isaMap[ext])
end
end
end
if #cfg.preview > 0 then
for _, opt in ipairs(cfg.preview) do
table.insert(flags, "-preview=" .. opt)
end
end
if #cfg.revert > 0 then
for _, opt in ipairs(cfg.revert) do
table.insert(flags, "-revert=" .. opt)
end
end
if #cfg.transition > 0 then
for _, opt in ipairs(cfg.transition) do
table.insert(flags, "-transition=" .. opt)
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=' .. p.quoted(dir))
end
return result
end
--
-- Decorate import file search paths for the DMD command line.
--
function ldc.getstringimportdirs(cfg, dirs)
local result = {}
for _, dir in ipairs(dirs) do
dir = project.getrelative(cfg.project, dir)
table.insert(result, '-J=' .. p.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 == p.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

View File

@@ -0,0 +1,9 @@
return {
"_preload.lua",
"gmake.lua",
"gmake_cpp.lua",
"gmake_csharp.lua",
"gmake_makefile.lua",
"gmake_utility.lua",
"gmake_workspace.lua",
}

View File

@@ -0,0 +1,64 @@
--
-- _preload.lua
-- Define the makefile action(s).
-- Copyright (c) 2002-2015 Jason Perkins and the Premake project
--
local p = premake
local project = p.project
---
-- The GNU make action, with support for the new platforms API
---
newaction {
trigger = "gmake",
shortname = "GNU Make",
description = "Generate GNU makefiles for POSIX, MinGW, and Cygwin",
toolset = "gcc",
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Utility", "Makefile" },
valid_languages = { "C", "C++", "C#" },
valid_tools = {
cc = { "clang", "gcc" },
dotnet = { "mono", "msnet", "pnet" }
},
onWorkspace = function(wks)
p.escaper(p.make.esc)
p.generate(wks, p.make.getmakefilename(wks, false), p.make.generate_workspace)
end,
onProject = function(prj)
p.escaper(p.make.esc)
local makefile = p.make.getmakefilename(prj, true)
if prj.kind == p.UTILITY then
p.generate(prj, makefile, p.make.utility.generate)
elseif prj.kind == p.MAKEFILE then
p.generate(prj, makefile, p.make.makefile.generate)
else
if project.isdotnet(prj) then
p.generate(prj, makefile, p.make.cs.generate)
elseif project.isc(prj) or project.iscpp(prj) then
p.generate(prj, makefile, p.make.cpp.generate)
end
end
end,
onCleanWorkspace = function(wks)
p.clean.file(wks, p.make.getmakefilename(wks, false))
end,
onCleanProject = function(prj)
p.clean.file(prj, p.make.getmakefilename(prj, true))
end
}
--
-- Decide when the full module should be loaded.
--
return function(cfg)
return (_ACTION == "gmake")
end

View File

@@ -0,0 +1,302 @@
--
-- gmake.lua
-- Define the makefile action(s).
-- Copyright (c) 2002-2015 Jason Perkins and the Premake project
--
local p = premake
p.modules.gmake = {}
p.modules.gmake._VERSION = p._VERSION
-- for backwards compatibility.
p.make = p.modules.gmake
local make = p.make
local project = p.project
--
-- Write out the default configuration rule for a workspace or project.
--
-- @param target
-- The workspace or project object for which a makefile is being generated.
--
function make.defaultconfig(target)
-- find the right configuration iterator function for this object
local eachconfig = iif(target.project, project.eachconfig, p.workspace.eachconfig)
local defaultconfig = nil
-- find the right default configuration platform, grab first configuration that matches
if target.defaultplatform then
for cfg in eachconfig(target) do
if cfg.platform == target.defaultplatform then
defaultconfig = cfg
break
end
end
end
-- grab the first configuration and write the block
if not defaultconfig then
local iter = eachconfig(target)
defaultconfig = iter()
end
if defaultconfig then
_p('ifndef config')
_x(' config=%s', defaultconfig.shortname)
_p('endif')
_p('')
end
end
---
-- Escape a string so it can be written to a makefile.
---
function make.esc(value)
result = value:gsub("\\", "\\\\")
result = result:gsub("\"", "\\\"")
result = result:gsub(" ", "\\ ")
result = result:gsub("%(", "\\(")
result = result:gsub("%)", "\\)")
-- leave $(...) shell replacement sequences alone
result = result:gsub("$\\%((.-)\\%)", "$(%1)")
return result
end
--
-- Get the makefile file name for a workspace or a project. If this object is the
-- only one writing to a location then I can use "Makefile". If more than one object
-- writes to the same location I use name + ".make" to keep it unique.
--
function make.getmakefilename(this, searchprjs)
local count = 0
for wks in p.global.eachWorkspace() do
if wks.location == this.location then
count = count + 1
end
if searchprjs then
for _, prj in ipairs(wks.projects) do
if prj.location == this.location then
count = count + 1
end
end
end
end
if count == 1 then
return "Makefile"
else
return ".make"
end
end
--
-- Output a makefile header.
--
-- @param target
-- The workspace or project object for which the makefile is being generated.
--
function make.header(target)
local kind = iif(target.project, "project", "workspace")
_p('# %s %s makefile autogenerated by Premake', p.action.current().shortname, kind)
_p('')
if kind == "workspace" then
local haspch = false
for _, prj in ipairs(target.projects) do
for cfg in project.eachconfig(prj) do
if cfg.pchheader then
haspch = true
end
end
end
if haspch then
_p('.NOTPARALLEL:')
_p('')
end
end
make.defaultconfig(target)
_p('ifndef verbose')
_p(' SILENT = @')
_p('endif')
_p('')
end
--
-- Rules for file ops based on the shell type. Can't use defines and $@ because
-- it screws up the escaping of spaces and parethesis (anyone know a fix?)
--
function make.mkdir(dirname)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) mkdir -p %s', dirname)
_p('else')
_p('\t$(SILENT) mkdir $(subst /,\\\\,%s)', dirname)
_p('endif')
end
function make.mkdirRules(dirname)
_p('%s:', dirname)
_p('\t@echo Creating %s', dirname)
make.mkdir(dirname)
_p('')
end
--
-- Format a list of values to be safely written as part of a variable assignment.
--
function make.list(value, quoted)
quoted = false
if #value > 0 then
if quoted then
local result = ""
for _, v in ipairs (value) do
if #result then
result = result .. " "
end
result = result .. p.quoted(v)
end
return result
else
return " " .. table.concat(value, " ")
end
else
return ""
end
end
--
-- Convert an arbitrary string (project name) to a make variable name.
--
function make.tovar(value)
value = value:gsub("[ -]", "_")
value = value:gsub("[()]", "")
return value
end
---------------------------------------------------------------------------
--
-- Handlers for the individual makefile elements that can be shared
-- between the different language projects.
--
---------------------------------------------------------------------------
function make.objdir(cfg)
_x(' OBJDIR = %s', p.esc(project.getrelative(cfg.project, cfg.objdir)))
end
function make.objDirRules(prj)
make.mkdirRules("$(OBJDIR)")
end
function make.phonyRules(prj)
_p('.PHONY: clean prebuild prelink')
_p('')
end
function make.buildCmds(cfg, event)
_p(' define %sCMDS', event:upper())
local steps = cfg[event .. "commands"]
local msg = cfg[event .. "message"]
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
msg = msg or string.format("Running %s commands", event)
_p('\t@echo %s', msg)
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p(' endef')
end
function make.preBuildCmds(cfg, toolset)
make.buildCmds(cfg, "prebuild")
end
function make.preBuildRules(prj)
_p('prebuild:')
_p('\t$(PREBUILDCMDS)')
_p('')
end
function make.preLinkCmds(cfg, toolset)
make.buildCmds(cfg, "prelink")
end
function make.preLinkRules(prj)
_p('prelink:')
_p('\t$(PRELINKCMDS)')
_p('')
end
function make.postBuildCmds(cfg, toolset)
make.buildCmds(cfg, "postbuild")
end
function make.settings(cfg, toolset)
if #cfg.makesettings > 0 then
for _, value in ipairs(cfg.makesettings) do
_p(value)
end
end
local value = toolset.getmakesettings(cfg)
if value then
_p(value)
end
end
function make.shellType()
_p('SHELLTYPE := posix')
_p('ifeq (.exe,$(findstring .exe,$(ComSpec)))')
_p('\tSHELLTYPE := msdos')
_p('endif')
_p('')
end
function make.target(cfg)
_x(' TARGETDIR = %s', project.getrelative(cfg.project, cfg.buildtarget.directory))
_x(' TARGET = $(TARGETDIR)/%s', cfg.buildtarget.name)
end
function make.targetDirRules(prj)
make.mkdirRules("$(TARGETDIR)")
end
include("gmake_cpp.lua")
include("gmake_csharp.lua")
include("gmake_makefile.lua")
include("gmake_utility.lua")
include("gmake_workspace.lua")
return p.modules.gmake

View File

@@ -0,0 +1,599 @@
--
-- make_cpp.lua
-- Generate a C/C++ project makefile.
-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
--
local p = premake
p.make.cpp = {}
local make = p.make
local cpp = p.make.cpp
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for p.callarray()
---
cpp.elements = {}
--
-- Generate a GNU make C++ project makefile, with support for the new platforms API.
--
cpp.elements.makefile = function(prj)
return {
make.header,
make.phonyRules,
make.cppConfigs,
make.cppObjects,
make.shellType,
make.cppTargetRules,
make.cppCustomFilesRules,
make.cppTargetDirRules,
make.cppObjDirRules,
make.cppCleanRules,
make.preBuildRules,
make.preLinkRules,
make.pchRules,
make.cppFileRules,
make.cppDependencies,
}
end
-- should be part of the toolset?
function make.fileTypeExtensions()
return {
["objects"] = "o",
["resources"] = "res",
}
end
-- should be part of the toolset?
function make.fileType(node)
local kind
if path.iscppfile(node.abspath) then
kind = "objects"
elseif path.isresourcefile(node.abspath) then
kind = "resources"
end
return kind
end
function make.fileDependency(prj, node)
local filetype = make.fileType(node)
_x('$(OBJDIR)/%s.%s: %s', node.objname, make.fileTypeExtensions()[filetype], node.relpath)
_p('\t@echo $(notdir $<)')
end
function make.cpp.generate(prj)
p.eol("\n")
p.callArray(cpp.elements.makefile, prj)
end
--
-- Write out the commands for compiling a file
--
cpp.elements.standardFileRules = function(prj, node)
return {
make.fileDependency,
cpp.standardFileRules,
}
end
cpp.elements.customFileRules = function(prj, node)
return {
make.fileDependency,
cpp.customFileRules,
}
end
cpp.elements.customBuildRules = function(prj, node)
return {
cpp.customFileRules
}
end
--
-- Write out the settings for a particular configuration.
--
cpp.elements.configuration = function(cfg, toolset)
return {
make.configBegin,
make.cppTools,
make.target,
make.objdir,
make.pch,
make.defines,
make.includes,
make.forceInclude,
make.cppFlags,
make.cFlags,
make.cxxFlags,
make.resFlags,
make.libs,
make.ldDeps,
make.ldFlags,
make.linkCmd,
make.exePaths,
make.preBuildCmds,
make.preLinkCmds,
make.postBuildCmds,
make.cppAllRules,
make.settings,
make.configEnd,
}
end
function make.cppConfigs(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.cc or cfg.toolset or "gcc"]
if not toolset then
error("Invalid toolset '" .. cfg.toolset .. "'")
end
p.callArray(cpp.elements.configuration, cfg, toolset)
_p('')
end
end
function make.exePaths(cfg)
local dirs = project.getrelative(cfg.project, cfg.bindirs)
if #dirs > 0 then
_p(' EXECUTABLE_PATHS = "%s"', table.concat(dirs, ":"))
_p(' EXE_PATHS = export PATH=$(EXECUTABLE_PATHS):$$PATH;')
end
end
--
-- Return the start of the compilation string that corresponds to the 'compileas' enum if set
--
function cpp.compileas(prj, node)
local result
if node["compileas"] then
if p.languages.isc(node.compileas) or node.compileas == p.OBJECTIVEC then
result = '$(CC) $(ALL_CFLAGS)'
elseif p.languages.iscpp(node.compileas) or node.compileas == p.OBJECTIVECPP then
result = '$(CXX) $(ALL_CXXFLAGS)'
end
end
return result
end
--
-- Build command for a single file.
--
function cpp.buildcommand(prj, objext, node)
local flags = cpp.compileas(prj, node)
if not flags then
local iscfile = node and path.iscfile(node.abspath) or false
flags = iif(prj.language == "C" or iscfile, '$(CC) $(ALL_CFLAGS)', '$(CXX) $(ALL_CXXFLAGS)')
end
_p('\t$(SILENT) %s $(FORCE_INCLUDE) -o "$@" -MF "$(@:%%.%s=%%.d)" -c "$<"', flags, objext)
end
--
-- Output the list of file building rules.
--
function make.cppFileRules(prj)
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
-- check to see if this file has custom rules
local rules
for cfg in project.eachconfig(prj) do
local filecfg = fileconfig.getconfig(node, cfg)
if fileconfig.hasCustomBuildRule(filecfg) then
rules = cpp.elements.customBuildRules(prj, node)
break
end
if fileconfig.hasFileSettings(filecfg) then
rules = cpp.elements.customFileRules(prj, node)
break
end
end
if not rules and make.fileType(node) then
rules = cpp.elements.standardFileRules(prj, node)
end
if rules then
p.callArray(rules, prj, node)
end
end
})
_p('')
end
function cpp.standardFileRules(prj, node)
local kind = make.fileType(node)
-- C/C++ file
if kind == "objects" then
cpp.buildcommand(prj, make.fileTypeExtensions()[kind], node)
-- resource file
elseif kind == "resources" then
_p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(ALL_RESFLAGS)')
end
end
function cpp.customFileRules(prj, node)
for cfg in project.eachconfig(prj) do
local filecfg = fileconfig.getconfig(node, cfg)
if filecfg then
make.configBegin(cfg)
if fileconfig.hasCustomBuildRule(filecfg) then
local output = project.getrelative(prj, filecfg.buildoutputs[1])
local dependencies = filecfg.relpath
if filecfg.buildinputs and #filecfg.buildinputs > 0 then
local inputs = project.getrelative(prj, filecfg.buildinputs)
dependencies = dependencies .. " " .. table.concat(p.esc(inputs), " ")
end
_p('%s: %s', output, dependencies)
_p('\t@echo "%s"', filecfg.buildmessage or ("Building " .. filecfg.relpath))
local cmds = os.translateCommandsAndPaths(filecfg.buildcommands, cfg.project.basedir, cfg.project.location)
for _, cmd in ipairs(cmds) do
if cfg.bindirs and #cfg.bindirs > 0 then
_p('\t$(SILENT) $(EXE_PATHS) %s', cmd)
else
_p('\t$(SILENT) %s', cmd)
end
end
else
cpp.standardFileRules(prj, filecfg)
end
make.configEnd(cfg)
end
end
end
--
-- List the objects file for the project, and each configuration.
--
function make.cppObjects(prj)
-- create lists for intermediate files, at the project level and
-- for each configuration
local root = { objects={}, resources={}, customfiles={} }
local configs = {}
for cfg in project.eachconfig(prj) do
configs[cfg] = { objects={}, resources={}, customfiles={} }
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
-- identify the file type
local kind
if path.iscppfile(node.abspath) then
kind = "objects"
elseif path.isresourcefile(node.abspath) then
kind = "resources"
end
-- skip files that aren't compiled
if not custom and not kind then
return
end
-- assign a unique object file name to avoid collisions
objectname = "$(OBJDIR)/" .. node.objname .. iif(kind == "objects", ".o", ".res")
-- 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[kind], objectname)
else
for cfg in project.eachconfig(prj) do
if incfg[cfg] then
table.insert(configs[cfg][kind], objectname)
end
end
end
else
for cfg in project.eachconfig(prj) do
local filecfg = incfg[cfg]
if filecfg then
local output = project.getrelative(prj, filecfg.buildoutputs[1])
if path.isobjectfile(output) and (filecfg.linkbuildoutputs == true or filecfg.linkbuildoutputs == nil) then
table.insert(configs[cfg].objects, output)
else
table.insert(configs[cfg].customfiles, output)
end
end
end
end
end
})
-- 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
listobjects('OBJECTS :=', root.objects, 'o')
listobjects('RESOURCES :=', root.resources, 'res')
listobjects('CUSTOMFILES :=', root.customfiles)
-- ...then individual configurations, as needed
for cfg in project.eachconfig(prj) do
local files = configs[cfg]
if #files.objects > 0 or #files.resources > 0 or #files.customfiles > 0 then
make.configBegin(cfg, toolset)
if #files.objects > 0 then
listobjects(' OBJECTS +=', files.objects)
end
if #files.resources > 0 then
listobjects(' RESOURCES +=', files.resources)
end
if #files.customfiles > 0 then
listobjects(' CUSTOMFILES +=', files.customfiles)
end
make.configEnd(cfg, toolset)
_p('')
end
end
end
---------------------------------------------------------------------------
--
-- Handlers for individual makefile elements
--
---------------------------------------------------------------------------
function make.configBegin(cfg, toolset)
if cfg then
_x('ifeq ($(config),%s)', cfg.shortname)
end
end
function make.configEnd(cfg, toolset)
if cfg then
_p('endif')
end
end
function make.cFlags(cfg, toolset)
_p(' ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)%s', make.list(table.join(toolset.getcflags(cfg), cfg.buildoptions)))
end
function make.cppAllRules(cfg, toolset)
if cfg.system == p.MACOSX and cfg.kind == p.WINDOWEDAPP then
_p('all: prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist')
_p('\t@:')
_p('')
_p('$(dir $(TARGETDIR))PkgInfo:')
_p('$(dir $(TARGETDIR))Info.plist:')
else
_p('all: prebuild prelink $(TARGET)')
_p('\t@:')
end
end
function make.cppFlags(cfg, toolset)
_p(' ALL_CPPFLAGS += $(CPPFLAGS)%s $(DEFINES) $(INCLUDES)', make.list(toolset.getcppflags(cfg)))
end
function make.cxxFlags(cfg, toolset)
_p(' ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)%s', make.list(table.join(toolset.getcxxflags(cfg), cfg.buildoptions)))
end
function make.cppCleanRules(prj)
_p('clean:')
_p('\t@echo Cleaning %s', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) rm -f $(TARGET)')
_p('\t$(SILENT) rm -rf $(OBJDIR)')
_p('else')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
_p('endif')
_p('')
end
function make.cppDependencies(prj)
-- include the dependencies, built by GCC (with the -MMD flag)
_p('-include $(OBJECTS:%%.o=%%.d)')
_p('ifneq (,$(PCH))')
_p(' -include $(OBJDIR)/$(notdir $(PCH)).d')
_p('endif')
end
function make.cppTargetRules(prj)
_p('$(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES) | $(TARGETDIR)')
_p('\t@echo Linking %s', prj.name)
_p('\t$(SILENT) $(LINKCMD)')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function make.cppCustomFilesRules(prj)
_p('$(CUSTOMFILES): | $(OBJDIR)')
_p('')
end
function make.cppTargetDirRules(prj)
_p('$(TARGETDIR):')
_p('\t@echo Creating $(TARGETDIR)')
make.mkdir('$(TARGETDIR)')
_p('')
end
function make.cppObjDirRules(prj)
_p('$(OBJDIR):')
_p('\t@echo Creating $(OBJDIR)')
make.mkdir('$(OBJDIR)')
_p('')
end
function make.cppTools(cfg, toolset)
local tool = toolset.gettoolname(cfg, "cc")
if tool then
_p(' ifeq ($(origin CC), default)')
_p(' CC = %s', tool)
_p(' endif' )
end
tool = toolset.gettoolname(cfg, "cxx")
if tool then
_p(' ifeq ($(origin CXX), default)')
_p(' CXX = %s', tool)
_p(' endif' )
end
tool = toolset.gettoolname(cfg, "ar")
if tool then
_p(' ifeq ($(origin AR), default)')
_p(' AR = %s', tool)
_p(' endif' )
end
tool = toolset.gettoolname(cfg, "rc")
if tool then
_p(' RESCOMP = %s', tool)
end
end
function make.defines(cfg, toolset)
_p(' DEFINES +=%s', make.list(table.join(toolset.getdefines(cfg.defines, cfg), toolset.getundefines(cfg.undefines))))
end
function make.forceInclude(cfg, toolset)
local includes = toolset.getforceincludes(cfg)
if not cfg.flags.NoPCH and cfg.pchheader then
table.insert(includes, 1, "-include $(OBJDIR)/$(notdir $(PCH))")
end
_x(' FORCE_INCLUDE +=%s', make.list(includes))
end
function make.includes(cfg, toolset)
local includes = toolset.getincludedirs(cfg, cfg.includedirs, cfg.sysincludedirs, cfg.frameworkdirs)
_p(' INCLUDES +=%s', make.list(includes))
end
function make.ldDeps(cfg, toolset)
local deps = config.getlinks(cfg, "siblings", "fullpath")
_p(' LDDEPS +=%s', make.list(p.esc(deps)))
end
function make.ldFlags(cfg, toolset)
local flags = table.join(toolset.getLibraryDirectories(cfg), toolset.getrunpathdirs(cfg, table.join(cfg.runpathdirs, config.getsiblingtargetdirs(cfg))), toolset.getldflags(cfg), cfg.linkoptions)
_p(' ALL_LDFLAGS += $(LDFLAGS)%s', make.list(flags))
end
function make.libs(cfg, toolset)
local flags = toolset.getlinks(cfg)
_p(' LIBS +=%s', make.list(flags, true))
end
function make.linkCmd(cfg, toolset)
if cfg.kind == p.STATICLIB then
if cfg.architecture == p.UNIVERSAL then
_p(' LINKCMD = libtool -o "$@" $(OBJECTS)')
else
_p(' LINKCMD = $(AR) ' .. (toolset.arargs or '-rcs') ..' "$@" $(OBJECTS)')
end
elseif cfg.kind == p.UTILITY then
-- Empty LINKCMD for Utility (only custom build rules)
_p(' LINKCMD =')
else
-- this was $(TARGET) $(LDFLAGS) $(OBJECTS)
-- but had trouble linking to certain static libs; $(OBJECTS) moved up
-- $(LDFLAGS) moved to end (http://sourceforge.net/p/premake/patches/107/)
-- $(LIBS) moved to end (http://sourceforge.net/p/premake/bugs/279/)
local cc = iif(p.languages.isc(cfg.language), "CC", "CXX")
_p(' LINKCMD = $(%s) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)', cc)
end
end
function make.pch(cfg, toolset)
local pch = p.tools.gcc.getpch(cfg)
-- If there is no header, or if PCH has been disabled, I can early out
if pch == nil then
return
end
_x(' PCH = %s', pch)
_p(' GCH = $(OBJDIR)/$(notdir $(PCH)).gch')
end
function make.pchRules(prj)
_p('ifneq (,$(PCH))')
_p('$(OBJECTS): $(GCH) $(PCH) | $(OBJDIR)')
_p('$(GCH): $(PCH) | $(OBJDIR)')
_p('\t@echo $(notdir $<)')
local cmd = iif(prj.language == "C", "$(CC) -x c-header $(ALL_CFLAGS)", "$(CXX) -x c++-header $(ALL_CXXFLAGS)")
_p('\t$(SILENT) %s -o "$@" -MF "$(@:%%.gch=%%.d)" -c "$<"', cmd)
_p('else')
_p('$(OBJECTS): | $(OBJDIR)')
_p('endif')
_p('')
end
function make.resFlags(cfg, toolset)
local resflags = table.join(toolset.getdefines(cfg.resdefines), toolset.getincludedirs(cfg, cfg.resincludedirs), cfg.resoptions)
_p(' ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)%s', make.list(resflags))
end

View File

@@ -0,0 +1,315 @@
--
-- make_csharp.lua
-- Generate a C# project makefile.
-- Copyright (c) 2002-2013 Jason Perkins and the Premake project
--
local p = premake
p.make.cs = {}
local make = p.make
local cs = p.make.cs
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
--
-- Add namespace for element definition lists for p.callarray()
--
cs.elements = {}
--
-- Generate a GNU make C++ project makefile, with support for the new platforms API.
--
cs.elements.makefile = function(prj)
return {
make.header,
make.phonyRules,
make.csConfigs,
make.csProjectConfig,
make.csSources,
make.csEmbedFiles,
make.csCopyFiles,
make.csResponseFile,
make.shellType,
make.csAllRules,
make.csTargetRules,
make.targetDirRules,
make.csResponseRules,
make.objDirRules,
make.csCleanRules,
make.preBuildRules,
make.preLinkRules,
make.csFileRules,
}
end
--
-- Generate a GNU make C# project makefile, with support for the new platforms API.
--
function make.cs.generate(prj)
p.eol("\n")
local toolset = p.tools.dotnet
p.callArray(cs.elements.makefile, prj, toolset)
end
--
-- Write out the settings for a particular configuration.
--
cs.elements.configuration = function(cfg)
return {
make.csTools,
make.target,
make.objdir,
make.csFlags,
make.csLinkCmd,
make.preBuildCmds,
make.preLinkCmds,
make.postBuildCmds,
make.settings,
}
end
function make.csConfigs(prj, toolset)
for cfg in project.eachconfig(prj) do
_x('ifeq ($(config),%s)', cfg.shortname)
p.callArray(cs.elements.configuration, cfg, toolset)
_p('endif')
_p('')
end
end
--
-- Given a .resx resource file, builds the path to corresponding .resource
-- file, matching the behavior and naming of Visual Studio.
--
function cs.getresourcefilename(cfg, fname)
if path.getextension(fname) == ".resx" then
local name = cfg.buildtarget.basename .. "."
local dir = path.getdirectory(fname)
if dir ~= "." then
name = name .. path.translate(dir, ".") .. "."
end
return "$(OBJDIR)/" .. p.esc(name .. path.getbasename(fname)) .. ".resources"
else
return fname
end
end
--
-- Iterate and output some selection of the source code files.
--
function cs.listsources(prj, selector)
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
local value = selector(node)
if value then
_x('\t%s \\', value)
end
end
})
end
---------------------------------------------------------------------------
--
-- Handlers for individual makefile elements
--
---------------------------------------------------------------------------
function make.csAllRules(prj, toolset)
_p('all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET)')
_p('')
end
function make.csCleanRules(prj, toolset)
--[[
-- porting from 4.x
_p('clean:')
_p('\t@echo Cleaning %s', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) rm -f $(TARGETDIR)/%s.* $(COPYFILES)', target.basename)
_p('\t$(SILENT) rm -rf $(OBJDIR)')
_p('else')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', target.name, target.basename)
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
for target, source in pairs(copypairs) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
_p('endif')
_p('')
--]]
end
function make.csCopyFiles(prj, toolset)
--[[
-- copied from 4.x; needs more porting
_p('COPYFILES += \\')
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t%s \\', target)
end
for target, source in pairs(copypairs) do
_p('\t%s \\', target)
end
_p('')
--]]
end
function make.cs.getresponsefilename(prj)
return '$(OBJDIR)/' .. prj.filename .. '.rsp'
end
function make.csResponseFile(prj, toolset)
_x('RESPONSE += ' .. make.cs.getresponsefilename(prj))
end
function make.csResponseRules(prj)
local toolset = p.tools.dotnet
local ext = make.getmakefilename(prj, true)
local makefile = path.getname(p.filename(prj, ext))
local response = make.cs.getresponsefilename(prj)
_p('$(RESPONSE): %s', makefile)
_p('\t@echo Generating response file', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_x('\t$(SILENT) rm -f $(RESPONSE)')
_p('else')
_x('\t$(SILENT) if exist $(RESPONSE) del %s', path.translate(response, '\\'))
_p('endif')
local sep = os.istarget("windows") and "\\" or "/"
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
if toolset.fileinfo(node).action == "Compile" then
_x('\t@echo %s >> $(RESPONSE)', path.translate(node.relpath, sep))
end
end
})
_p('')
end
function make.csEmbedFiles(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('EMBEDFILES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "EmbeddedResource" then
return cs.getresourcefilename(cfg, node.relpath)
end
end)
_p('')
end
function make.csFileRules(prj, toolset)
--[[
-- porting from 4.x
_p('# Per-configuration copied file rules')
for cfg in p.eachconfig(prj) do
_x('ifneq (,$(findstring %s,$(config)))', cfg.name:lower())
for target, source in pairs(cfgpairs[cfg]) do
p.make_copyrule(source, target)
end
_p('endif')
_p('')
end
_p('# Copied file rules')
for target, source in pairs(copypairs) do
p.make_copyrule(source, target)
end
_p('# Embedded file rules')
for _, fname in ipairs(embedded) do
if path.getextension(fname) == ".resx" then
_x('%s: %s', getresourcefilename(prj, fname), fname)
_p('\t$(SILENT) $(RESGEN) $^ $@')
end
_p('')
end
--]]
end
function make.csFlags(cfg, toolset)
_p(' FLAGS =%s', make.list(toolset.getflags(cfg)))
end
function make.csLinkCmd(cfg, toolset)
local deps = p.esc(config.getlinks(cfg, "dependencies", "fullpath"))
_p(' DEPENDS =%s', make.list(deps))
_p(' REFERENCES = %s', table.implode(deps, "/r:", "", " "))
end
function make.csProjectConfig(prj, toolset)
-- To maintain compatibility with Visual Studio, these values must
-- be set on the project level, and not per-configuration.
local cfg = project.getfirstconfig(prj)
local kindflag = "/t:" .. toolset.getkind(cfg):lower()
local libdirs = table.implode(p.esc(cfg.libdirs), "/lib:", "", " ")
_p('FLAGS += %s', table.concat(table.join(kindflag, libdirs), " "))
local refs = p.esc(config.getlinks(cfg, "system", "fullpath"))
_p('REFERENCES += %s', table.implode(refs, "/r:", "", " "))
_p('')
end
function make.csSources(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('SOURCES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "Compile" then
return node.relpath
end
end)
_p('')
end
function make.csTargetRules(prj, toolset)
_p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(RESPONSE)')
_p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) @$(RESPONSE) $(patsubst %%,/resource:%%,$(EMBEDFILES))')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function make.csTools(cfg, toolset)
_p(' CSC = %s', toolset.gettoolname(cfg, "csc"))
_p(' RESGEN = %s', toolset.gettoolname(cfg, "resgen"))
end

View File

@@ -0,0 +1,93 @@
--
-- make_makefile.lua
-- Generate a C/C++ project makefile.
-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
--
local p = premake
p.make.makefile = {}
local make = p.make
local makefile = p.make.makefile
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for p.callarray()
---
makefile.elements = {}
--
-- Generate a GNU make makefile project makefile.
--
makefile.elements.makefile = {
"header",
"phonyRules",
"makefileConfigs",
"makefileTargetRules"
}
function make.makefile.generate(prj)
p.eol("\n")
p.callarray(make, makefile.elements.makefile, prj)
end
makefile.elements.configuration = {
"target",
"buildCommands",
"cleanCommands",
}
function make.makefileConfigs(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[cfg.toolset or "gcc"]
if not toolset then
error("Invalid toolset '" .. cfg.toolset .. "'")
end
_x('ifeq ($(config),%s)', cfg.shortname)
p.callarray(make, makefile.elements.configuration, cfg, toolset)
_p('endif')
_p('')
end
end
function make.makefileTargetRules(prj)
_p('$(TARGET):')
_p('\t$(BUILDCMDS)')
_p('')
_p('clean:')
_p('\t$(CLEANCMDS)')
_p('')
end
function make.buildCommands(cfg)
_p(' define BUILDCMDS')
local steps = cfg.buildcommands
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
_p('\t@echo Running build commands')
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p(' endef')
end
function make.cleanCommands(cfg)
_p(' define CLEANCMDS')
local steps = cfg.cleancommands
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
_p('\t@echo Running clean commands')
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p(' endef')
end

View File

@@ -0,0 +1,67 @@
--
-- make_utility.lua
-- Generate a C/C++ project makefile.
-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
--
local p = premake
p.make.utility = {}
local make = p.make
local utility = p.make.utility
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for p.callarray()
---
utility.elements = {}
--
-- Generate a GNU make utility project makefile.
--
utility.elements.makefile = {
"header",
"phonyRules",
"utilityConfigs",
"utilityTargetRules"
}
function make.utility.generate(prj)
p.eol("\n")
p.callarray(make, utility.elements.makefile, prj)
end
utility.elements.configuration = {
"target",
"preBuildCmds",
"postBuildCmds",
}
function make.utilityConfigs(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[cfg.toolset or "gcc"]
if not toolset then
error("Invalid toolset '" .. cfg.toolset .. "'")
end
_x('ifeq ($(config),%s)', cfg.shortname)
p.callarray(make, utility.elements.configuration, cfg, toolset)
_p('endif')
_p('')
end
end
function make.utilityTargetRules(prj)
_p('$(TARGET):')
_p('\t$(PREBUILDCMDS)')
_p('\t$(POSTBUILDCMDS)')
_p('')
end

View File

@@ -0,0 +1,188 @@
--
-- make_workspace.lua
-- Generate a workspace-level makefile.
-- Copyright (c) 2002-2015 Jason Perkins and the Premake project
--
local p = premake
local make = p.make
local tree = p.tree
local project = p.project
--
-- Generate a GNU make "workspace" makefile, with support for the new platforms API.
--
function make.generate_workspace(wks)
p.eol("\n")
make.header(wks)
make.configmap(wks)
make.projects(wks)
make.workspacePhonyRule(wks)
make.groupRules(wks)
make.projectrules(wks)
make.cleanrules(wks)
make.helprule(wks)
end
--
-- Write out the workspace's configuration map, which maps workspace
-- level configurations to the project level equivalents.
--
function make.configmap(wks)
for cfg in p.workspace.eachconfig(wks) do
_p('ifeq ($(config),%s)', cfg.shortname)
for prj in p.workspace.eachproject(wks) do
local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
if prjcfg then
_p(' %s_config = %s', make.tovar(prj.name), prjcfg.shortname)
end
end
_p('endif')
end
_p('')
end
--
-- Write out the rules for the `make clean` action.
--
function make.cleanrules(wks)
_p('clean:')
for prj in p.workspace.eachproject(wks) do
local prjpath = p.filename(prj, make.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
local prjname = path.getname(prjpath)
_x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname)
end
_p('')
end
--
-- Write out the make file help rule and configurations list.
--
function make.helprule(wks)
_p('help:')
_p(1,'@echo "Usage: make [config=name] [target]"')
_p(1,'@echo ""')
_p(1,'@echo "CONFIGURATIONS:"')
for cfg in p.workspace.eachconfig(wks) do
_x(1, '@echo " %s"', cfg.shortname)
end
_p(1,'@echo ""')
_p(1,'@echo "TARGETS:"')
_p(1,'@echo " all (default)"')
_p(1,'@echo " clean"')
for prj in p.workspace.eachproject(wks) do
_p(1,'@echo " %s"', prj.name)
end
_p(1,'@echo ""')
_p(1,'@echo "For more information, see https://github.com/premake/premake-core/wiki"')
end
--
-- Write out the list of projects that comprise the workspace.
--
function make.projects(wks)
_p('PROJECTS := %s', table.concat(p.esc(table.extract(wks.projects, "name")), " "))
_p('')
end
--
-- Write out the workspace PHONY rule
--
function make.workspacePhonyRule(wks)
local groups = {}
local tr = p.workspace.grouptree(wks)
tree.traverse(tr, {
onbranch = function(n)
table.insert(groups, n.path)
end
})
_p('.PHONY: all clean help $(PROJECTS) ' .. table.implode(groups, '', '', ' '))
_p('')
_p('all: $(PROJECTS)')
_p('')
end
--
-- Write out the phony rules representing project groups
--
function make.groupRules(wks)
-- Transform workspace groups into target aggregate
local tr = p.workspace.grouptree(wks)
tree.traverse(tr, {
onbranch = function(n)
local rule = n.path .. ":"
local projectTargets = {}
local groupTargets = {}
for i, c in pairs(n.children)
do
if type(i) == "string"
then
if c.project
then
table.insert(projectTargets, c.name)
else
table.insert(groupTargets, c.path)
end
end
end
if #groupTargets > 0 then
table.sort(groupTargets)
rule = rule .. " " .. table.concat(groupTargets, " ")
end
if #projectTargets > 0 then
table.sort(projectTargets)
rule = rule .. " " .. table.concat(projectTargets, " ")
end
_p(rule)
_p('')
end
})
end
--
-- Write out the rules to build each of the workspace's projects.
--
function make.projectrules(wks)
for prj in p.workspace.eachproject(wks) do
local deps = project.getdependencies(prj)
deps = table.extract(deps, "name")
_p('%s:%s', p.esc(prj.name), make.list(deps))
local cfgvar = make.tovar(prj.name)
_p('ifneq (,$(%s_config))', cfgvar)
_p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar)
local prjpath = p.filename(prj, make.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
local prjname = path.getname(prjpath)
_x(1,'@${MAKE} --no-print-directory -C %s -f %s config=$(%s_config)', prjdir, prjname, cfgvar)
_p('endif')
_p('')
end
end

View File

@@ -0,0 +1,33 @@
require ("gmake")
return {
-- Makefile tests
"test_make_escaping.lua",
"test_make_tovar.lua",
-- Makefile workspaces
"workspace/test_config_maps.lua",
"workspace/test_default_config.lua",
"workspace/test_group_rule.lua",
"workspace/test_help_rule.lua",
"workspace/test_project_rule.lua",
-- Makefile C/C++ projects
"cpp/test_clang.lua",
"cpp/test_file_rules.lua",
"cpp/test_flags.lua",
"cpp/test_ldflags.lua",
"cpp/test_make_pch.lua",
"cpp/test_make_linking.lua",
"cpp/test_objects.lua",
"cpp/test_target_rules.lua",
"cpp/test_tools.lua",
"cpp/test_wiidev.lua",
-- Makefile C# projects
"cs/test_embed_files.lua",
"cs/test_flags.lua",
"cs/test_links.lua",
"cs/test_response.lua",
"cs/test_sources.lua",
}

View File

@@ -0,0 +1,63 @@
--
-- tests/actions/make/cpp/test_clang.lua
-- Test Clang support in Makefiles.
-- Copyright (c) 2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_clang")
local make = p.make
local cpp = p.make.cpp
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks = test.createWorkspace()
toolset "clang"
prj = p.workspace.getproject(wks, 1)
end
--
-- Make sure that the correct compilers are used.
--
function suite.usesCorrectCompilers()
make.cppConfigs(prj)
test.capture [[
ifeq ($(config),debug)
ifeq ($(origin CC), default)
CC = clang
endif
ifeq ($(origin CXX), default)
CXX = clang++
endif
ifeq ($(origin AR), default)
AR = ar
endif
]]
end
function suite.usesCorrectCompilersAndLinkTimeOptimization()
flags { "LinkTimeOptimization" }
make.cppConfigs(prj)
test.capture [[
ifeq ($(config),debug)
ifeq ($(origin CC), default)
CC = clang
endif
ifeq ($(origin CXX), default)
CXX = clang++
endif
ifeq ($(origin AR), default)
AR = llvm-ar
endif
]]
end

View File

@@ -0,0 +1,170 @@
--
-- tests/actions/make/cpp/test_file_rules.lua
-- Validate the makefile source building rules.
-- Copyright (c) 2009-2014 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cpp_file_rules")
local make = p.make
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
p.escaper(make.esc)
wks = test.createWorkspace()
end
local function prepare()
prj = p.workspace.getproject(wks, 1)
make.cppFileRules(prj)
end
--
-- Two files with the same base name should have different object files.
--
function suite.uniqueObjNames_onBaseNameCollision()
files { "src/hello.cpp", "src/greetings/hello.cpp" }
prepare()
test.capture [[
$(OBJDIR)/hello.o: src/greetings/hello.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/hello1.o: src/hello.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects should been compiled as c
--
function suite.cFilesGetsCompiledWithCCWhileInCppProject()
files { "src/hello.c", "src/test.cpp" }
prepare()
test.capture [[
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/test.o: src/test.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects can be compiled as C++ with 'compileas'
--
function suite.cFilesGetsCompiledWithCXXWithCompileas()
files { "src/hello.c", "src/test.c" }
filter { "files:src/hello.c" }
compileas "C++"
prepare()
test.capture [[
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
ifeq ($(config),debug)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
endif
ifeq ($(config),release)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
endif
$(OBJDIR)/test.o: src/test.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects can be compiled as C++ with 'compileas' on a configuration basis
--
function suite.cFilesGetsCompiledWithCXXWithCompileasDebugOnly()
files { "src/test.c", "src/hello.c" }
filter { "configurations:Debug", "files:src/hello.c" }
compileas "C++"
prepare()
test.capture [[
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
ifeq ($(config),debug)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
endif
ifeq ($(config),release)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
endif
$(OBJDIR)/test.o: src/test.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- If a custom build rule is supplied, it should be used.
--
function suite.customBuildRule()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
prepare()
test.capture [[
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
endif
ifeq ($(config),release)
obj/Release/hello.obj: hello.x
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
endif
]]
end
function suite.customBuildRuleWithAdditionalInputs()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
buildinputs { "%{file.path}.inc", "%{file.path}.inc2" }
prepare()
test.capture [[
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x hello.x.inc hello.x.inc2
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
endif
ifeq ($(config),release)
obj/Release/hello.obj: hello.x hello.x.inc hello.x.inc2
@echo "Compiling hello.x"
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
endif
]]
end

View File

@@ -0,0 +1,144 @@
--
-- tests/actions/make/cpp/test_flags.lua
-- Tests compiler and linker flags for Makefiles.
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_flags")
local make = p.make
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
p.callarray(make, calls, cfg, toolset)
end
--
-- Include directories should be relative and space separated.
--
function suite.includeDirs()
includedirs { "src/include", "../include" }
prepare { "includes" }
test.capture [[
INCLUDES += -Isrc/include -I../include
]]
end
--
-- symbols "on" should produce -g
--
function suite.symbols_on()
symbols "on"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
--
-- symbols default to 'off'
--
function suite.symbols_default()
symbols "default"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end
--
-- All other symbols flags also produce -g
--
function suite.symbols_fastlink()
symbols "FastLink"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
function suite.symbols_full()
symbols "full"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
--
-- symbols "off" should not produce -g
--
function suite.symbols_off()
symbols "off"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end
--
-- symbols "on" with a proper debugformat should produce a corresponding -g
--
function suite.symbols_on_default()
symbols "on"
debugformat "Default"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
function suite.symbols_on_dwarf()
symbols "on"
debugformat "Dwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -gdwarf
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -gdwarf
]]
end
function suite.symbols_on_split_dwarf()
symbols "on"
debugformat "SplitDwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -gsplit-dwarf
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -gsplit-dwarf
]]
end
--
-- symbols "off" with a proper debugformat should not produce -g
--
function suite.symbols_off_dwarf()
symbols "off"
debugformat "Dwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end

View File

@@ -0,0 +1,78 @@
--
-- tests/actions/make/cpp/test_ldflags.lua
-- Tests compiler and linker flags for Makefiles.
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_ldflags")
local make = p.make
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
symbols "On"
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
make.ldFlags(cfg, toolset)
end
--
-- Check the output from default project values.
--
function suite.checkDefaultValues()
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS)
]]
end
--
-- Check addition of library search directores.
--
function suite.checkLibDirs()
libdirs { "../libs", "libs" }
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L../libs -Llibs
]]
end
function suite.checkLibDirs_X86_64()
architecture ("x86_64")
system (p.LINUX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
]]
end
function suite.checkLibDirs_X86()
architecture ("x86")
system (p.LINUX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
]]
end
function suite.checkLibDirs_X86_64_MacOSX()
architecture ("x86_64")
system (p.MACOSX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -m64
]]
end

View File

@@ -0,0 +1,270 @@
--
-- tests/actions/make/cpp/test_make_linking.lua
-- Validate the link step generation for makefiles.
-- Copyright (c) 2010-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_linking")
local make = p.make
local project = p.project
--
-- Setup and teardown
--
local wks, prj
function suite.setup()
_TARGET_OS = "linux"
wks, prj = test.createWorkspace()
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
p.callarray(make, calls, cfg, toolset)
end
--
-- Check link command for a shared C++ library.
--
function suite.links_onCppSharedLib()
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -shared -Wl,-soname=libMyProject.so -s
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
function suite.links_onMacOSXCppSharedLib()
_TARGET_OS = "macosx"
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -dynamiclib -Wl,-install_name,@rpath/libMyProject.dylib -Wl,-x
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
--
-- Check link command for a shared C library.
--
function suite.links_onCSharedLib()
language "C"
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -shared -Wl,-soname=libMyProject.so -s
LINKCMD = $(CC) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
--
-- Check link command for a static library.
--
function suite.links_onStaticLib()
kind "StaticLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LINKCMD = $(AR) -rcs "$@" $(OBJECTS)
]]
end
--
-- Check link command for the Utility kind.
--
-- Utility projects should only run custom commands, and perform no linking.
--
function suite.links_onUtility()
kind "Utility"
prepare { "linkCmd" }
test.capture [[
LINKCMD =
]]
end
--
-- Check link command for a Mac OS X universal static library.
--
function suite.links_onMacUniversalStaticLib()
architecture "universal"
kind "StaticLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LINKCMD = libtool -o "$@" $(OBJECTS)
]]
end
--
-- Check a linking to a sibling static library.
--
function suite.links_onSiblingStaticLib()
links "MyProject2"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += build/bin/Debug/libMyProject2.a
LDDEPS += build/bin/Debug/libMyProject2.a
]]
end
--
-- Check a linking to a sibling shared library.
--
function suite.links_onSiblingSharedLib()
links "MyProject2"
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Wl,-rpath,'$$ORIGIN/../../build/bin/Debug' -s
LIBS += build/bin/Debug/libMyProject2.so
LDDEPS += build/bin/Debug/libMyProject2.so
]]
end
--
-- Check a linking to a sibling shared library using -l and -L.
--
function suite.links_onSiblingSharedLibRelativeLinks()
links "MyProject2"
flags { "RelativeLinks" }
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'$$ORIGIN/../../build/bin/Debug' -s
LIBS += -lMyProject2
LDDEPS += build/bin/Debug/libMyProject2.so
]]
end
function suite.links_onMacOSXSiblingSharedLib()
_TARGET_OS = "macosx"
links "MyProject2"
flags { "RelativeLinks" }
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'@loader_path/../../build/bin/Debug' -Wl,-x
LIBS += -lMyProject2
LDDEPS += build/bin/Debug/libMyProject2.dylib
]]
end
--
-- Check a linking multiple siblings.
--
function suite.links_onMultipleSiblingStaticLib()
links "MyProject2"
links "MyProject3"
test.createproject(wks)
kind "StaticLib"
location "build"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
LDDEPS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
]]
end
--
-- Check a linking multiple siblings with link groups enabled.
--
function suite.links_onSiblingStaticLibWithLinkGroups()
links "MyProject2"
links "MyProject3"
linkgroups "On"
test.createproject(wks)
kind "StaticLib"
location "build"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += -Wl,--start-group build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a -Wl,--end-group
LDDEPS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
]]
end
--
-- When referencing an external library via a path, the directory
-- should be added to the library search paths, and the library
-- itself included via an -l flag.
--
function suite.onExternalLibraryWithPath()
location "MyProject"
links { "libs/SomeLib" }
prepare { "ldFlags", "libs" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L../libs -s
LIBS += -lSomeLib
]]
end
--
-- When referencing an external library with a period in the
-- file name make sure it appears correctly in the LIBS
-- directive. Currently the period and everything after it
-- is stripped
--
function suite.onExternalLibraryWithPathAndVersion()
location "MyProject"
links { "libs/SomeLib-1.1" }
prepare { "libs", }
test.capture [[
LIBS += -lSomeLib-1.1
]]
end

View File

@@ -0,0 +1,142 @@
--
-- tests/actions/make/cpp/test_make_pch.lua
-- Validate the setup for precompiled headers in makefiles.
-- Copyright (c) 2010-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_pch")
local make = p.make
local project = p.project
--
-- Setup and teardown
--
local wks, prj
function suite.setup()
os.chdir(_TESTS_DIR)
wks, prj = test.createWorkspace()
end
local function prepareVars()
local cfg = test.getconfig(prj, "Debug")
make.pch(cfg)
end
local function prepareRules()
local cfg = test.getconfig(prj, "Debug")
make.pchRules(cfg.project)
end
--
-- If no header has been set, nothing should be output.
--
function suite.noConfig_onNoHeaderSet()
prepareVars()
test.isemptycapture()
end
--
-- If a header is set, but the NoPCH flag is also set, then
-- nothing should be output.
--
function suite.noConfig_onHeaderAndNoPCHFlag()
pchheader "include/myproject.h"
flags "NoPCH"
prepareVars()
test.isemptycapture()
end
--
-- If a header is specified and the NoPCH flag is not set, then
-- the header can be used.
--
function suite.config_onPchEnabled()
pchheader "include/myproject.h"
prepareVars()
test.capture [[
PCH = include/myproject.h
GCH = $(OBJDIR)/$(notdir $(PCH)).gch
]]
end
--
-- The PCH can be specified relative the an includes search path.
--
function suite.pch_searchesIncludeDirs()
pchheader "premake.h"
includedirs { "../../../src/host" }
prepareVars()
test.capture [[
PCH = ../../../src/host/premake.h
]]
end
--
-- Verify the format of the PCH rules block for a C++ file.
--
function suite.buildRules_onCpp()
pchheader "include/myproject.h"
prepareRules()
test.capture [[
ifneq (,$(PCH))
$(OBJECTS): $(GCH) $(PCH) | $(OBJDIR)
$(GCH): $(PCH) | $(OBJDIR)
@echo $(notdir $<)
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
else
$(OBJECTS): | $(OBJDIR)
endif
]]
end
--
-- Verify the format of the PCH rules block for a C file.
--
function suite.buildRules_onC()
language "C"
pchheader "include/myproject.h"
prepareRules()
test.capture [[
ifneq (,$(PCH))
$(OBJECTS): $(GCH) $(PCH) | $(OBJDIR)
$(GCH): $(PCH) | $(OBJDIR)
@echo $(notdir $<)
$(SILENT) $(CC) -x c-header $(ALL_CFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
else
$(OBJECTS): | $(OBJDIR)
endif
]]
end
--
-- If the header is located on one of the include file
-- search directories, it should get found automatically.
--
function suite.findsPCH_onIncludeDirs()
location "MyProject"
pchheader "premake.h"
includedirs { "../../../src/host" }
prepareVars()
test.capture [[
PCH = ../../../../src/host/premake.h
]]
end

View File

@@ -0,0 +1,250 @@
--
-- tests/actions/make/cpp/test_objects.lua
-- Validate the list of objects for a makefile.
-- Copyright (c) 2009-2015 Jason Perkins and the Premake project
--
local suite = test.declare("make_cpp_objects")
local p = premake
--
-- Setup
--
local wks, prj
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
p.make.cppObjects(prj)
end
--
-- If a file is listed at the project level, it should get listed in
-- the project level objects list.
--
function suite.listFileInProjectObjects()
files { "src/hello.cpp" }
prepare()
test.capture [[
OBJECTS := \
$(OBJDIR)/hello.o \
]]
end
--
-- Only buildable files should be listed.
--
function suite.onlyListBuildableFiles()
files { "include/gl.h", "src/hello.cpp" }
prepare()
test.capture [[
OBJECTS := \
$(OBJDIR)/hello.o \
]]
end
--
-- A file should only be listed in the configurations to which it belongs.
--
function suite.configFilesAreConditioned()
filter "Debug"
files { "src/hello_debug.cpp" }
filter "Release"
files { "src/hello_release.cpp" }
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),debug)
OBJECTS += \
$(OBJDIR)/hello_debug.o \
endif
ifeq ($(config),release)
OBJECTS += \
$(OBJDIR)/hello_release.o \
endif
]]
end
--
-- Two files with the same base name should have different object files.
--
function suite.uniqueObjNames_onBaseNameCollision()
files { "src/hello.cpp", "src/greetings/hello.cpp" }
prepare()
test.capture [[
OBJECTS := \
$(OBJDIR)/hello.o \
$(OBJDIR)/hello1.o \
]]
end
--
-- If a custom rule builds to an object file, include it in the
-- link automatically to match the behavior of Visual Studio
--
function suite.linkBuildOutputs_onNotSpecified()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),debug)
OBJECTS += \
obj/Debug/hello.obj \
endif
]]
end
--
-- Also include it in the link step if we explicitly specified so with
-- linkbuildoutputs.
--
function suite.linkBuildOutputs_onOn()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
linkbuildoutputs "On"
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),debug)
OBJECTS += \
obj/Debug/hello.obj \
endif
]]
end
--
-- If linkbuildoutputs says that we shouldn't include it in the link however,
-- don't do it.
--
function suite.linkBuildOutputs_onOff()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
linkbuildoutputs "Off"
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),debug)
CUSTOMFILES += \
obj/Debug/hello.obj \
endif
]]
end
--
-- If a file is excluded from a configuration, it should not be listed.
--
function suite.excludedFromBuild_onExcludedFile()
files { "hello.cpp" }
filter "Debug"
removefiles { "hello.cpp" }
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),release)
OBJECTS += \
$(OBJDIR)/hello.o \
endif
]]
end
function suite.excludedFromBuild_onExcludeFlag()
files { "hello.cpp" }
filter { "Debug", "files:hello.cpp" }
flags { "ExcludeFromBuild" }
prepare()
test.capture [[
OBJECTS := \
RESOURCES := \
CUSTOMFILES := \
ifeq ($(config),release)
OBJECTS += \
$(OBJDIR)/hello.o \
endif
]]
end

View File

@@ -0,0 +1,57 @@
--
-- tests/actions/make/cpp/test_target_rules.lua
-- Validate the makefile target building rules.
-- Copyright (c) 2009-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cpp_target_rules")
local make = p.make
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare()
local cfg = test.getconfig(prj, "Debug")
make.cppAllRules(cfg)
end
--
-- Check the default, normal format of the rules.
--
function suite.defaultRules()
prepare()
test.capture [[
all: prebuild prelink $(TARGET)
@:
]]
end
--
-- Check rules for an OS X Cocoa application.
--
function suite.osxWindowedAppRules()
system "MacOSX"
kind "WindowedApp"
prepare()
test.capture [[
all: prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist
@:
$(dir $(TARGETDIR))PkgInfo:
$(dir $(TARGETDIR))Info.plist:
]]
end

View File

@@ -0,0 +1,35 @@
--
-- tests/actions/make/cpp/test_tools.lua
-- Tests for tools support in makefiles.
-- Copyright (c) 2012-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_tools")
local make = p.make
local cpp = p.make.cpp
local project = p.project
--
-- Setup
--
local cfg
function suite.setup()
local wks, prj = test.createWorkspace()
cfg = test.getconfig(prj, "Debug")
end
--
-- Make sure that the correct tools are used.
--
function suite.usesCorrectTools()
make.cppTools(cfg, p.tools.gcc)
test.capture [[
RESCOMP = windres
]]
end

View File

@@ -0,0 +1,58 @@
--
-- tests/actions/make/cpp/test_wiidev.lua
-- Tests for Wii homebrew support in makefiles.
-- Copyright (c) 2011-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_wiidev")
local make = p.make
local project = p.project
--
-- Setup
--
local cfg
function suite.setup()
local wks, prj = test.createWorkspace()
system "wii"
symbols "On"
cfg = test.getconfig(prj, "Debug")
end
--
-- Make sure that the Wii-specific flags are passed to the tools.
--
function suite.writesCorrectCppFlags()
make.cppFlags(cfg, p.tools.gcc)
test.capture [[
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -I$(LIBOGC_INC) $(MACHDEP) $(DEFINES) $(INCLUDES)
]]
end
function suite.writesCorrectLinkerFlags()
make.ldFlags(cfg, p.tools.gcc)
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L$(LIBOGC_LIB) $(MACHDEP)
]]
end
--
-- Make sure the dev kit include is written to each Wii build configuration.
--
function suite.writesIncludeBlock()
make.settings(cfg, p.tools.gcc)
test.capture [[
ifeq ($(strip $(DEVKITPPC)),)
$(error "DEVKITPPC environment variable is not set")'
endif
include $(DEVKITPPC)/wii_rules'
]]
end

View File

@@ -0,0 +1,75 @@
--
-- tests/actions/make/cs/test_embed_files.lua
-- Tests embedded file listings for C# Makefiles.
-- Copyright (c) 2013-2014 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cs_embed_files")
local make = p.make
local cs = p.make.cs
local project = p.project
--
-- Setup
--
local wks, prj, cfg
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
prj = p.workspace.getproject(wks, 1)
make.csEmbedFiles(prj, p.tools.dotnet)
end
--
-- Files that can be compiled should be listed here.
--
function suite.doesListResourceFiles()
files { "Hello.resx" }
prepare()
test.capture [[
EMBEDFILES += \
$(OBJDIR)/MyProject.Hello.resources \
]]
end
--
-- Files that should not be compiled should be excluded.
--
function suite.doesIgnoreNonResourceFiles()
files { "About.txt", "Hello.resx" }
prepare()
test.capture [[
EMBEDFILES += \
$(OBJDIR)/MyProject.Hello.resources \
]]
end
--
-- Files with a non-standard file extension but a build action of
-- "Embed" should be listed here.
--
function suite.doesIncludeCompileBuildAction()
files { "Hello.txt" }
filter "files:*.txt"
buildaction "Embed"
prepare()
test.capture [[
EMBEDFILES += \
Hello.txt \
]]
end

View File

@@ -0,0 +1,65 @@
--
-- tests/actions/make/cs/test_flags.lua
-- Tests compiler and linker flags for C# Makefiles.
-- Copyright (c) 2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cs_flags")
local make = p.make
local cs = p.make.cs
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare()
local cfg = test.getconfig(prj, "Debug")
make.csFlags(cfg, p.tools.dotnet)
end
--
-- Should return an empty assignment if nothing has been specified.
--
function suite.isEmptyAssignment_onNoSettings()
prepare()
test.capture [[
FLAGS = /noconfig
]]
end
--
-- If the Unsafe flag has been set, it should be specified.
--
function suite.onUnsafe()
clr "Unsafe"
prepare()
test.capture [[
FLAGS = /unsafe /noconfig
]]
end
--
-- If an application icon has been set, it should be specified.
--
function suite.onApplicationIcon()
icon "MyProject.ico"
prepare()
test.capture [[
FLAGS = /noconfig /win32icon:"MyProject.ico"
]]
end

View File

@@ -0,0 +1,60 @@
--
-- tests/actions/make/cs/test_links.lua
-- Tests linking for C# Makefiles.
-- Copyright (c) 2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cs_links")
local make = p.make
local cs = p.make.cs
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare()
local cfg = test.getconfig(prj, "Debug")
make.csLinkCmd(cfg, p.tools.dotnet)
end
--
-- Should return an empty assignment if nothing has been specified.
--
function suite.isEmptyAssignment_onNoSettings()
prepare()
test.capture [[
DEPENDS =
]]
end
--
-- Files that can be compiled should be listed here.
--
function suite.doesListLinkDependencyFiles()
links { "MyProject2", "MyProject3" }
test.createproject(wks)
kind "SharedLib"
language "C#"
test.createproject(wks)
kind "SharedLib"
language "C#"
prepare ()
test.capture [[
DEPENDS = bin/Debug/MyProject2.dll bin/Debug/MyProject3.dll
]]
end

View File

@@ -0,0 +1,90 @@
--
-- tests/actions/make/cs/test_response.lua
-- Validate the list of objects for a response file used by a makefile.
-- Copyright (c) 2009-2013 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cs_response")
local make = p.make
--
-- Setup
--
local wks, prj
function suite.setup()
p.action.set("vs2010")
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
end
--
-- Create a project with a lot of files to force the generation of response files.
-- This makes sure they can be processed in Windows since else we reach the command
-- line length max limit.
--
function suite.listResponse()
prepare()
make.csResponseFile(prj)
test.capture [[
RESPONSE += $(OBJDIR)/MyProject.rsp
]]
end
function suite.listResponseTargets()
prepare()
make.csTargetRules(prj)
test.capture [[
$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(RESPONSE)
$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) @$(RESPONSE) $(patsubst %,/resource:%,$(EMBEDFILES))
]]
end
function suite.listResponseRules()
files { "foo.cs", "bar.cs", "dir/foo.cs" }
prepare()
make.csResponseRules(prj)
end
function suite.listResponseRulesPosix()
_TARGET_OS = "linux"
suite.listResponseRules()
test.capture [[
$(RESPONSE): MyProject.make
@echo Generating response file
ifeq (posix,$(SHELLTYPE))
$(SILENT) rm -f $(RESPONSE)
else
$(SILENT) if exist $(RESPONSE) del $(OBJDIR)\MyProject.rsp
endif
@echo bar.cs >> $(RESPONSE)
@echo dir/foo.cs >> $(RESPONSE)
@echo foo.cs >> $(RESPONSE)
]]
end
function suite.listResponseRulesWindows()
_TARGET_OS = "windows"
suite.listResponseRules()
test.capture [[
$(RESPONSE): MyProject.make
@echo Generating response file
ifeq (posix,$(SHELLTYPE))
$(SILENT) rm -f $(RESPONSE)
else
$(SILENT) if exist $(RESPONSE) del $(OBJDIR)\MyProject.rsp
endif
@echo bar.cs >> $(RESPONSE)
@echo dir\foo.cs >> $(RESPONSE)
@echo foo.cs >> $(RESPONSE)
]]
end

View File

@@ -0,0 +1,90 @@
--
-- tests/actions/make/cs/test_sources.lua
-- Tests source file listings for C# Makefiles.
-- Copyright (c) 2013-2014 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_cs_sources")
local make = p.make
local cs = p.make.cs
local project = p.project
--
-- Setup
--
local wks, prj, cfg
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
prj = p.workspace.getproject(wks, 1)
make.csSources(prj, p.tools.dotnet)
end
--
-- Files that can be compiled should be listed here.
--
function suite.doesListSourceFiles()
files { "Hello.cs" }
prepare()
test.capture [[
SOURCES += \
Hello.cs \
]]
end
--
-- Path delimiter uses slash instead of backslash
--
function suite.doesUseProperPathDelimiter()
files { "Folder\\Hello.cs", "Folder/World.cs" }
prepare()
test.capture [[
SOURCES += \
Folder/Hello.cs \
Folder/World.cs \
]]
end
--
-- Files that should not be compiled should be excluded.
--
function suite.doesIgnoreNonSourceFiles()
files { "About.txt", "Hello.cs" }
prepare()
test.capture [[
SOURCES += \
Hello.cs \
]]
end
--
-- Files with a non-standard file extension but a build action of
-- "Compile" should be listed here.
--
function suite.doesIncludeCompileBuildAction()
files { "Hello.txt" }
filter "files:*.txt"
buildaction "Compile"
prepare()
test.capture [[
SOURCES += \
Hello.txt \
]]
end

View File

@@ -0,0 +1,31 @@
--
-- tests/actions/make/test_make_escaping.lua
-- Validate the escaping of literal values in Makefiles.
-- Copyright (c) 2010-2012 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_escaping")
local make = p.make
function suite.Escapes_Spaces()
test.isequal([[Program\ Files]], make.esc([[Program Files]]))
end
function suite.Escapes_Backslashes()
test.isequal([[Program\\Files]], make.esc([[Program\Files]]))
end
function suite.Escapes_Parens()
test.isequal([[Debug\(x86\)]], make.esc([[Debug(x86)]]))
end
function suite.DoesNotEscape_ShellReplacements()
test.isequal([[-L$(NVSDKCUDA_ROOT)/C/lib]], make.esc([[-L$(NVSDKCUDA_ROOT)/C/lib]]))
end
function suite.CanEscape_ShellReplacementCapturesShortest()
test.isequal([[a\(x\)b$(ROOT)c\(y\)d]], make.esc([[a(x)b$(ROOT)c(y)d]]))
end

View File

@@ -0,0 +1,35 @@
--
-- tests/actions/make/test_make_tovar.lua
-- Test translation of strings to make variable names.
-- Copyright (c) 2012 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_tovar")
local make = p.make
--
-- Convert spaces to underscores.
--
function suite.removesSpaces()
test.isequal("My_Project", make.tovar("My Project"))
end
--
-- Convert dashes to underscores.
--
function suite.removesDashes()
test.isequal("My_Project", make.tovar("My-Project"))
end
--
-- Remove parenthesis.
--
function suite.removesParenthesis()
test.isequal("MyProject_x86", make.tovar("MyProject (x86)"))
end

View File

@@ -0,0 +1,78 @@
--
-- tests/actions/make/test_config_maps.lua
-- Validate handling of configuration maps in makefiles.
-- Copyright (c) 2012 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_config_maps")
local make = p.make
--
-- Setup/teardown
--
local wks, prj
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
make.configmap(wks)
end
--
-- If no map is present, the configurations should pass through
-- to the projects unchanged.
--
function suite.passesThroughConfigs_onNoMap()
prepare()
test.capture [[
ifeq ($(config),debug)
MyProject_config = debug
endif
ifeq ($(config),release)
MyProject_config = release
endif
]]
end
--
-- If a map is present, the configuration change should be applied.
--
function suite.passesThroughConfigs_onMap()
configmap { Debug = "Development" }
prepare()
test.capture [[
ifeq ($(config),debug)
MyProject_config = development
endif
ifeq ($(config),release)
MyProject_config = release
endif
]]
end
--
-- If a configuration is not included in a particular project,
-- no mapping should be created.
--
function suite.passesThroughConfigs_onNoMapRemovedConfiguration()
removeconfigurations { "Debug" }
prepare()
test.capture [[
ifeq ($(config),debug)
endif
ifeq ($(config),release)
MyProject_config = release
endif
]]
end

View File

@@ -0,0 +1,87 @@
--
-- tests/actions/make/test_default_config.lua
-- Validate generation of default configuration block for makefiles.
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local suite = test.declare("make_default_config")
local p = premake
--
-- Setup/teardown
--
local wks, prj
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
p.make.defaultconfig(prj)
end
--
-- Verify the handling of the default setup: Debug and Release, no platforms.
--
function suite.defaultsToFirstBuildCfg_onNoPlatforms()
prepare()
test.capture [[
ifndef config
config=debug
endif
]]
end
--
-- Verify handling of build config/platform combination.
--
function suite.defaultsToFirstPairing_onPlatforms()
platforms { "Win32", "Win64" }
prepare()
test.capture [[
ifndef config
config=debug_win32
endif
]]
end
--
-- If the project excludes a workspace build cfg, it should be skipped
-- over as the default config as well.
--
function suite.usesFirstValidPairing_onExcludedConfig()
platforms { "Win32", "Win64" }
removeconfigurations { "Debug" }
prepare()
test.capture [[
ifndef config
config=release_win32
endif
]]
end
--
-- Verify handling of defaultplatform
--
function suite.defaultsToSpecifiedPlatform()
platforms { "Win32", "Win64" }
defaultplatform "Win64"
prepare()
test.capture [[
ifndef config
config=debug_win64
endif
]]
end

View File

@@ -0,0 +1,61 @@
--
-- tests/actions/make/workspace/test_group_rule.lua
-- Validate generation of group rules
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_group_rule")
local make = p.make
--
-- Setup/teardown
--
local wks
function suite.setup()
wks = test.createWorkspace()
group "MainGroup"
test.createproject(wks)
group "MainGroup/SubGroup1"
test.createproject(wks)
group "MainGroup/SubGroup2"
test.createproject(wks)
test.createproject(wks)
end
local function prepare()
wks = test.getWorkspace(wks)
end
--
-- Groups should be added to workspace's PHONY
--
function suite.groupRule_groupAsPhony()
prepare()
make.workspacePhonyRule(wks)
test.capture [[
.PHONY: all clean help $(PROJECTS) MainGroup MainGroup/SubGroup1 MainGroup/SubGroup2
]]
end
--
-- Transform workspace groups into target aggregate
--
function suite.groupRule_groupRules()
prepare()
make.groupRules(wks)
test.capture [[
MainGroup: MainGroup/SubGroup1 MainGroup/SubGroup2 MyProject2
MainGroup/SubGroup1: MyProject3
MainGroup/SubGroup2: MyProject4 MyProject5
]]
end

View File

@@ -0,0 +1,41 @@
--
-- tests/actions/make/test_help_rule.lua
-- Validate generation of help rule and configurations list.
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_help_rule")
--
-- Setup/teardown
--
local wks
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
wks = test.getWorkspace(wks)
p.make.helprule(wks)
end
--
-- Start with the default Debug and Release setup.
--
function suite.looksOkay_onDefaultSetup()
prepare()
test.capture [[
help:
@echo "Usage: make [config=name] [target]"
@echo ""
@echo "CONFIGURATIONS:"
@echo " debug"
@echo " release"
]]
end

View File

@@ -0,0 +1,42 @@
--
-- tests/actions/make/workspace/test_project_rule.lua
-- Validate generation of project rules in workspace makefile.
-- Copyright (c) 2012-2015 Jason Perkins and the Premake project
--
local p = premake
local suite = test.declare("make_project_rule")
--
-- Setup/teardown
--
local wks
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
p.oven.bake()
wks = test.getWorkspace(wks)
p.make.projectrules(wks)
end
--
-- Verify a simple project with no dependencies.
--
function suite.projectRule_onNoDependencies()
prepare()
test.capture [[
MyProject:
ifneq (,$(MyProject_config))
@echo "==== Building MyProject ($(MyProject_config)) ===="
@${MAKE} --no-print-directory -C . -f MyProject.make config=$(MyProject_config)
endif
]]
end

View File

@@ -0,0 +1,9 @@
return {
"_preload.lua",
"gmake2.lua",
"gmake2_cpp.lua",
"gmake2_csharp.lua",
"gmake2_makefile.lua",
"gmake2_utility.lua",
"gmake2_workspace.lua",
}

View File

@@ -0,0 +1,70 @@
--
-- Name: gmake2/_preload.lua
-- Purpose: Define the gmake2 action.
-- Author: Blizzard Entertainment (Tom van Dijck)
-- Modified by: Aleksi Juvani
-- Vlad Ivanov
-- Created: 2016/01/01
-- Copyright: (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local project = p.project
newaction {
trigger = "gmake2",
shortname = "Alternative GNU Make",
description = "Generate GNU makefiles for POSIX, MinGW, and Cygwin",
toolset = "gcc",
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Utility", "Makefile" },
valid_languages = { "C", "C++", "C#" },
valid_tools = {
cc = { "clang", "gcc" },
dotnet = { "mono", "msnet", "pnet" }
},
onInitialize = function()
require("gmake2")
p.modules.gmake2.cpp.initialize()
end,
onWorkspace = function(wks)
p.escaper(p.modules.gmake2.esc)
p.generate(wks, p.modules.gmake2.getmakefilename(wks, false), p.modules.gmake2.generate_workspace)
end,
onProject = function(prj)
p.escaper(p.modules.gmake2.esc)
local makefile = p.modules.gmake2.getmakefilename(prj, true)
if prj.kind == p.UTILITY then
p.generate(prj, makefile, p.modules.gmake2.utility.generate)
elseif prj.kind == p.MAKEFILE then
p.generate(prj, makefile, p.modules.gmake2.makefile.generate)
else
if project.isdotnet(prj) then
p.generate(prj, makefile, p.modules.gmake2.cs.generate)
elseif project.isc(prj) or project.iscpp(prj) then
p.generate(prj, makefile, p.modules.gmake2.cpp.generate)
end
end
end,
onCleanWorkspace = function(wks)
p.clean.file(wks, p.modules.gmake2.getmakefilename(wks, false))
end,
onCleanProject = function(prj)
p.clean.file(prj, p.modules.gmake2.getmakefilename(prj, true))
end
}
--
-- Decide when the full module should be loaded.
--
return function(cfg)
return (_ACTION == "gmake2")
end

View File

@@ -0,0 +1,348 @@
--
-- gmake2.lua
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local project = p.project
p.modules.gmake2 = {}
p.modules.gmake2._VERSION = p._VERSION
local gmake2 = p.modules.gmake2
--
-- Write out the default configuration rule for a workspace or project.
--
-- @param target
-- The workspace or project object for which a makefile is being generated.
--
function gmake2.defaultconfig(target)
-- find the right configuration iterator function for this object
local eachconfig = iif(target.project, project.eachconfig, p.workspace.eachconfig)
local defaultconfig = nil
-- find the right default configuration platform, grab first configuration that matches
if target.defaultplatform then
for cfg in eachconfig(target) do
if cfg.platform == target.defaultplatform then
defaultconfig = cfg
break
end
end
end
-- grab the first configuration and write the block
if not defaultconfig then
local iter = eachconfig(target)
defaultconfig = iter()
end
if defaultconfig then
_p('ifndef config')
_x(' config=%s', defaultconfig.shortname)
_p('endif')
_p('')
end
end
---
-- Escape a string so it can be written to a makefile.
---
function gmake2.esc(value)
result = value:gsub("\\", "\\\\")
result = result:gsub("\"", "\\\"")
result = result:gsub(" ", "\\ ")
result = result:gsub("%(", "\\(")
result = result:gsub("%)", "\\)")
-- leave $(...) shell replacement sequences alone
result = result:gsub("$\\%((.-)\\%)", "$(%1)")
return result
end
--
-- Get the makefile file name for a workspace or a project. If this object is the
-- only one writing to a location then I can use "Makefile". If more than one object
-- writes to the same location I use name + ".make" to keep it unique.
--
function gmake2.getmakefilename(this, searchprjs)
local count = 0
for wks in p.global.eachWorkspace() do
if wks.location == this.location then
count = count + 1
end
if searchprjs then
for _, prj in ipairs(wks.projects) do
if prj.location == this.location then
count = count + 1
end
end
end
end
if count == 1 then
return "Makefile"
else
return ".make"
end
end
--
-- Output a makefile header.
--
-- @param target
-- The workspace or project object for which the makefile is being generated.
--
function gmake2.header(target)
local kind = iif(target.project, "project", "workspace")
_p('# %s %s makefile autogenerated by Premake', p.action.current().shortname, kind)
_p('')
gmake2.defaultconfig(target)
_p('ifndef verbose')
_p(' SILENT = @')
_p('endif')
_p('')
end
--
-- Rules for file ops based on the shell type. Can't use defines and $@ because
-- it screws up the escaping of spaces and parethesis (anyone know a fix?)
--
function gmake2.mkdir(dirname)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) mkdir -p %s', dirname)
_p('else')
_p('\t$(SILENT) mkdir $(subst /,\\\\,%s)', dirname)
_p('endif')
end
function gmake2.mkdirRules(dirname)
_p('%s:', dirname)
_p('\t@echo Creating %s', dirname)
gmake2.mkdir(dirname)
_p('')
end
--
-- Format a list of values to be safely written as part of a variable assignment.
--
function gmake2.list(value, quoted)
quoted = false
if #value > 0 then
if quoted then
local result = ""
for _, v in ipairs (value) do
if #result then
result = result .. " "
end
result = result .. p.quoted(v)
end
return result
else
return " " .. table.concat(value, " ")
end
else
return ""
end
end
--
-- Convert an arbitrary string (project name) to a make variable name.
--
function gmake2.tovar(value)
value = value:gsub("[ -]", "_")
value = value:gsub("[()]", "")
return value
end
function gmake2.getToolSet(cfg)
local default = iif(cfg.system == p.MACOSX, "clang", "gcc")
local toolset = p.tools[_OPTIONS.cc or cfg.toolset or default]
if not toolset then
error("Invalid toolset '" .. cfg.toolset .. "'")
end
return toolset
end
function gmake2.outputSection(prj, callback)
local root = {}
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 = gmake2.getToolSet(cfg)
local settings = {}
local funcs = callback(cfg)
for i = 1, #funcs do
local c = p.capture(function ()
funcs[i](cfg, toolset)
end)
if #c > 0 then
table.insert(settings, c)
end
end
if not root.settings then
root.settings = table.arraycopy(settings)
else
root.settings = table.intersect(root.settings, settings)
end
root[cfg] = settings
end
if #root.settings > 0 then
for _, v in ipairs(root.settings) do
p.outln(v)
end
p.outln('')
end
local first = true
for cfg in project.eachconfig(prj) do
local settings = table.difference(root[cfg], root.settings)
if #settings > 0 then
if first then
_x('ifeq ($(config),%s)', cfg.shortname)
first = false
else
_x('else ifeq ($(config),%s)', cfg.shortname)
end
for k, v in ipairs(settings) do
p.outln(v)
end
_p('')
end
end
if not first then
p.outln('endif')
p.outln('')
end
end
-- convert a rule property into a string
---------------------------------------------------------------------------
--
-- Handlers for the individual makefile elements that can be shared
-- between the different language projects.
--
---------------------------------------------------------------------------
function gmake2.phonyRules(prj)
_p('.PHONY: clean prebuild')
_p('')
end
function gmake2.shellType()
_p('SHELLTYPE := posix')
_p('ifeq (.exe,$(findstring .exe,$(ComSpec)))')
_p('\tSHELLTYPE := msdos')
_p('endif')
_p('')
end
function gmake2.target(cfg, toolset)
p.outln('TARGETDIR = ' .. project.getrelative(cfg.project, cfg.buildtarget.directory))
p.outln('TARGET = $(TARGETDIR)/' .. cfg.buildtarget.name)
end
function gmake2.objdir(cfg, toolset)
p.outln('OBJDIR = ' .. project.getrelative(cfg.project, cfg.objdir))
end
function gmake2.settings(cfg, toolset)
if #cfg.makesettings > 0 then
for _, value in ipairs(cfg.makesettings) do
p.outln(value)
end
end
local value = toolset.getmakesettings(cfg)
if value then
p.outln(value)
end
end
function gmake2.buildCmds(cfg, event)
_p('define %sCMDS', event:upper())
local steps = cfg[event .. "commands"]
local msg = cfg[event .. "message"]
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
msg = msg or string.format("Running %s commands", event)
_p('\t@echo %s', msg)
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p('endef')
end
function gmake2.preBuildCmds(cfg, toolset)
gmake2.buildCmds(cfg, "prebuild")
end
function gmake2.preLinkCmds(cfg, toolset)
gmake2.buildCmds(cfg, "prelink")
end
function gmake2.postBuildCmds(cfg, toolset)
gmake2.buildCmds(cfg, "postbuild")
end
function gmake2.targetDirRules(cfg, toolset)
gmake2.mkdirRules("$(TARGETDIR)")
end
function gmake2.objDirRules(cfg, toolset)
gmake2.mkdirRules("$(OBJDIR)")
end
function gmake2.preBuildRules(cfg, toolset)
_p('prebuild: | $(OBJDIR)')
_p('\t$(PREBUILDCMDS)')
_p('')
end
include("gmake2_cpp.lua")
include("gmake2_csharp.lua")
include("gmake2_makefile.lua")
include("gmake2_utility.lua")
include("gmake2_workspace.lua")
return gmake2

View File

@@ -0,0 +1,787 @@
--
-- gmake2_cpp.lua
-- Generate a C/C++ project makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
gmake2.cpp = {}
local cpp = gmake2.cpp
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for premake.callarray()
---
cpp.elements = {}
--
-- Generate a GNU make C++ project makefile, with support for the new platforms API.
--
cpp.elements.makefile = function(prj)
return {
gmake2.header,
gmake2.phonyRules,
gmake2.shellType,
cpp.createRuleTable,
cpp.outputConfigurationSection,
cpp.outputPerFileConfigurationSection,
cpp.createFileTable,
cpp.outputFilesSection,
cpp.outputRulesSection,
cpp.outputFileRuleSection,
cpp.dependencies,
}
end
function cpp.generate(prj)
p.eol("\n")
p.callArray(cpp.elements.makefile, prj)
-- allow the garbage collector to clean things up.
for cfg in project.eachconfig(prj) do
cfg._gmake = nil
end
prj._gmake = nil
end
function cpp.initialize()
rule 'cpp'
fileExtension { ".cc", ".cpp", ".cxx", ".mm" }
buildoutputs { "$(OBJDIR)/%{file.objname}.o" }
buildmessage '$(notdir $<)'
buildcommands {'$(CXX) %{premake.modules.gmake2.cpp.fileFlags(cfg, file)} $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"'}
rule 'cc'
fileExtension {".c", ".s", ".m"}
buildoutputs { "$(OBJDIR)/%{file.objname}.o" }
buildmessage '$(notdir $<)'
buildcommands {'$(CC) %{premake.modules.gmake2.cpp.fileFlags(cfg, file)} $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"'}
rule 'resource'
fileExtension ".rc"
buildoutputs { "$(OBJDIR)/%{file.objname}.res" }
buildmessage '$(notdir $<)'
buildcommands {'$(RESCOMP) $< -O coff -o "$@" $(ALL_RESFLAGS)'}
global(nil)
end
function cpp.createRuleTable(prj)
local rules = {}
local function addRule(extension, rule)
if type(extension) == 'table' then
for _, value in ipairs(extension) do
addRule(value, rule)
end
else
rules[extension] = rule
end
end
-- add all rules.
local usedRules = table.join({'cpp', 'cc', 'resource'}, prj.rules)
for _, name in ipairs(usedRules) do
local rule = p.global.getRule(name)
addRule(rule.fileExtension, rule)
end
-- create fileset categories.
local filesets = {
['.o'] = 'OBJECTS',
['.obj'] = 'OBJECTS',
['.cc'] = 'SOURCES',
['.cpp'] = 'SOURCES',
['.cxx'] = 'SOURCES',
['.mm'] = 'SOURCES',
['.c'] = 'SOURCES',
['.s'] = 'SOURCES',
['.m'] = 'SOURCES',
['.rc'] = 'RESOURCES',
}
-- cache the result.
prj._gmake = prj._gmake or {}
prj._gmake.rules = rules
prj._gmake.filesets = filesets
end
function cpp.createFileTable(prj)
for cfg in project.eachconfig(prj) do
cfg._gmake = cfg._gmake or {}
cfg._gmake.filesets = {}
cfg._gmake.fileRules = {}
local files = table.shallowcopy(prj._.files)
table.foreachi(files, function(node)
cpp.addFile(cfg, node)
end)
for _, f in pairs(cfg._gmake.filesets) do
table.sort(f)
end
cfg._gmake.kinds = table.keys(cfg._gmake.filesets)
table.sort(cfg._gmake.kinds)
prj._gmake.kinds = table.join(prj._gmake.kinds or {}, cfg._gmake.kinds)
end
-- we need to reassign object sequences if we generated any files.
if prj.hasGeneratedFiles and p.project.iscpp(prj) then
p.oven.assignObjectSequences(prj)
end
prj._gmake.kinds = table.unique(prj._gmake.kinds)
table.sort(prj._gmake.kinds)
end
function cpp.addFile(cfg, node)
local filecfg = fileconfig.getconfig(node, cfg)
if not filecfg or filecfg.flags.ExcludeFromBuild then
return
end
-- skip generated files, since we try to figure it out manually below.
if node.generated then
return
end
-- process custom build commands.
if fileconfig.hasCustomBuildRule(filecfg) then
local env = table.shallowcopy(filecfg.environ)
env.PathVars = {
["file.basename"] = { absolute = false, token = node.basename },
["file.abspath"] = { absolute = true, token = node.abspath },
["file.relpath"] = { absolute = false, token = node.relpath },
["file.name"] = { absolute = false, token = node.name },
["file.objname"] = { absolute = false, token = node.objname },
["file.path"] = { absolute = true, token = node.path },
["file.directory"] = { absolute = true, token = path.getdirectory(node.abspath) },
["file.reldirectory"] = { absolute = false, token = path.getdirectory(node.relpath) },
}
local shadowContext = p.context.extent(filecfg, env)
local buildoutputs = p.project.getrelative(cfg.project, shadowContext.buildoutputs)
if buildoutputs and #buildoutputs > 0 then
local file = {
buildoutputs = buildoutputs,
source = node.relpath,
buildmessage = shadowContext.buildmessage,
buildcommands = shadowContext.buildcommands,
buildinputs = p.project.getrelative(cfg.project, shadowContext.buildinputs)
}
table.insert(cfg._gmake.fileRules, file)
for _, output in ipairs(buildoutputs) do
cpp.addGeneratedFile(cfg, node, output)
end
end
else
cpp.addRuleFile(cfg, node)
end
end
function cpp.determineFiletype(cfg, node)
-- determine which filetype to use
local filecfg = fileconfig.getconfig(node, cfg)
local fileext = path.getextension(node.abspath):lower()
if filecfg and filecfg.compileas then
if p.languages.isc(filecfg.compileas) then
fileext = ".c"
elseif p.languages.iscpp(filecfg.compileas) then
fileext = ".cpp"
end
end
return fileext;
end
function cpp.addGeneratedFile(cfg, source, filename)
-- mark that we have generated files.
cfg.project.hasGeneratedFiles = true
-- add generated file to the project.
local files = cfg.project._.files
local node = files[filename]
if not node then
node = fileconfig.new(filename, cfg.project)
files[filename] = node
table.insert(files, node)
end
-- always overwrite the dependency information.
node.dependsOn = source
node.generated = true
-- add to config if not already added.
if not fileconfig.getconfig(node, cfg) then
fileconfig.addconfig(node, cfg)
end
-- determine which filetype to use
local fileext = cpp.determineFiletype(cfg, node)
-- add file to the fileset.
local filesets = cfg.project._gmake.filesets
local kind = filesets[fileext] or "CUSTOM"
-- don't link generated object files automatically if it's explicitly
-- disabled.
if path.isobjectfile(filename) and source.linkbuildoutputs == false then
kind = "CUSTOM"
end
local fileset = cfg._gmake.filesets[kind] or {}
table.insert(fileset, filename)
cfg._gmake.filesets[kind] = fileset
local generatedKind = "GENERATED"
local generatedFileset = cfg._gmake.filesets[generatedKind] or {}
table.insert(generatedFileset, filename)
cfg._gmake.filesets[generatedKind] = generatedFileset
-- recursively setup rules.
cpp.addRuleFile(cfg, node)
end
function cpp.addRuleFile(cfg, node)
local rules = cfg.project._gmake.rules
local fileext = cpp.determineFiletype(cfg, node)
local rule = rules[fileext]
if rule then
local filecfg = fileconfig.getconfig(node, cfg)
local environ = table.shallowcopy(filecfg.environ)
if rule.propertydefinition then
p.rule.prepareEnvironment(rule, environ, cfg)
p.rule.prepareEnvironment(rule, environ, filecfg)
end
local shadowContext = p.context.extent(rule, environ)
local buildoutputs = shadowContext.buildoutputs
local buildmessage = shadowContext.buildmessage
local buildcommands = shadowContext.buildcommands
local buildinputs = shadowContext.buildinputs
buildoutputs = p.project.getrelative(cfg.project, buildoutputs)
if buildoutputs and #buildoutputs > 0 then
local file = {
buildoutputs = buildoutputs,
source = node.relpath,
buildmessage = buildmessage,
buildcommands = buildcommands,
buildinputs = buildinputs
}
table.insert(cfg._gmake.fileRules, file)
for _, output in ipairs(buildoutputs) do
cpp.addGeneratedFile(cfg, node, output)
end
end
end
end
--
-- Write out the settings for a particular configuration.
--
cpp.elements.configuration = function(cfg)
return {
cpp.tools,
gmake2.target,
gmake2.objdir,
cpp.pch,
cpp.defines,
cpp.includes,
cpp.forceInclude,
cpp.cppFlags,
cpp.cFlags,
cpp.cxxFlags,
cpp.resFlags,
cpp.libs,
cpp.ldDeps,
cpp.ldFlags,
cpp.linkCmd,
cpp.bindirs,
cpp.exepaths,
gmake2.settings,
gmake2.preBuildCmds,
gmake2.preLinkCmds,
gmake2.postBuildCmds,
}
end
function cpp.outputConfigurationSection(prj)
_p('# Configurations')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, cpp.elements.configuration)
end
function cpp.tools(cfg, toolset)
local tool = toolset.gettoolname(cfg, "cc")
if tool then
_p('ifeq ($(origin CC), default)')
_p(' CC = %s', tool)
_p('endif' )
end
tool = toolset.gettoolname(cfg, "cxx")
if tool then
_p('ifeq ($(origin CXX), default)')
_p(' CXX = %s', tool)
_p('endif' )
end
tool = toolset.gettoolname(cfg, "ar")
if tool then
_p('ifeq ($(origin AR), default)')
_p(' AR = %s', tool)
_p('endif' )
end
tool = toolset.gettoolname(cfg, "rc")
if tool then
_p('RESCOMP = %s', tool)
end
end
function cpp.pch(cfg, toolset)
local pch = p.tools.gcc.getpch(cfg)
-- If there is no header, or if PCH has been disabled, I can early out
if pch == nil then
return
end
p.outln('PCH = ' .. pch)
p.outln('PCH_PLACEHOLDER = $(OBJDIR)/$(notdir $(PCH))')
p.outln('GCH = $(PCH_PLACEHOLDER).gch')
end
function cpp.defines(cfg, toolset)
p.outln('DEFINES +=' .. gmake2.list(table.join(toolset.getdefines(cfg.defines, cfg), toolset.getundefines(cfg.undefines))))
end
function cpp.includes(cfg, toolset)
local includes = toolset.getincludedirs(cfg, cfg.includedirs, cfg.sysincludedirs, cfg.frameworkdirs)
p.outln('INCLUDES +=' .. gmake2.list(includes))
end
function cpp.forceInclude(cfg, toolset)
local includes = toolset.getforceincludes(cfg)
p.outln('FORCE_INCLUDE +=' .. gmake2.list(includes))
end
function cpp.cppFlags(cfg, toolset)
local flags = gmake2.list(toolset.getcppflags(cfg))
p.outln('ALL_CPPFLAGS += $(CPPFLAGS)' .. flags .. ' $(DEFINES) $(INCLUDES)')
end
function cpp.cFlags(cfg, toolset)
local flags = gmake2.list(table.join(toolset.getcflags(cfg), cfg.buildoptions))
p.outln('ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)' .. flags)
end
function cpp.cxxFlags(cfg, toolset)
local flags = gmake2.list(table.join(toolset.getcxxflags(cfg), cfg.buildoptions))
p.outln('ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)' .. flags)
end
function cpp.resFlags(cfg, toolset)
local resflags = table.join(toolset.getdefines(cfg.resdefines), toolset.getincludedirs(cfg, cfg.resincludedirs), cfg.resoptions)
p.outln('ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)' .. gmake2.list(resflags))
end
function cpp.libs(cfg, toolset)
local flags = toolset.getlinks(cfg)
p.outln('LIBS +=' .. gmake2.list(flags, true))
end
function cpp.ldDeps(cfg, toolset)
local deps = config.getlinks(cfg, "siblings", "fullpath")
p.outln('LDDEPS +=' .. gmake2.list(p.esc(deps)))
end
function cpp.ldFlags(cfg, toolset)
local flags = table.join(toolset.getLibraryDirectories(cfg), toolset.getrunpathdirs(cfg, table.join(cfg.runpathdirs, config.getsiblingtargetdirs(cfg))), toolset.getldflags(cfg), cfg.linkoptions)
p.outln('ALL_LDFLAGS += $(LDFLAGS)' .. gmake2.list(flags))
end
function cpp.linkCmd(cfg, toolset)
if cfg.kind == p.STATICLIB then
if cfg.architecture == p.UNIVERSAL then
p.outln('LINKCMD = libtool -o "$@" $(OBJECTS)')
else
p.outln('LINKCMD = $(AR) -rcs "$@" $(OBJECTS)')
end
elseif cfg.kind == p.UTILITY then
-- Empty LINKCMD for Utility (only custom build rules)
p.outln('LINKCMD =')
else
-- this was $(TARGET) $(LDFLAGS) $(OBJECTS)
-- but had trouble linking to certain static libs; $(OBJECTS) moved up
-- $(LDFLAGS) moved to end (http://sourceforge.net/p/premake/patches/107/)
-- $(LIBS) moved to end (http://sourceforge.net/p/premake/bugs/279/)
local cc = iif(p.languages.isc(cfg.language), "CC", "CXX")
p.outln('LINKCMD = $(' .. cc .. ') -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)')
end
end
function cpp.bindirs(cfg, toolset)
local dirs = project.getrelative(cfg.project, cfg.bindirs)
if #dirs > 0 then
p.outln('EXECUTABLE_PATHS = "' .. table.concat(dirs, ":") .. '"')
end
end
function cpp.exepaths(cfg, toolset)
local dirs = project.getrelative(cfg.project, cfg.bindirs)
if #dirs > 0 then
p.outln('EXE_PATHS = export PATH=$(EXECUTABLE_PATHS):$$PATH;')
end
end
--
-- Write out the per file configurations.
--
function cpp.outputPerFileConfigurationSection(prj)
_p('# Per File Configurations')
_p('# #############################################')
_p('')
for cfg in project.eachconfig(prj) do
table.foreachi(prj._.files, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
if fcfg then
cpp.perFileFlags(cfg, fcfg)
end
end)
end
_p('')
end
function cpp.makeVarName(prj, value, saltValue)
prj._gmake = prj._gmake or {}
prj._gmake.varlist = prj._gmake.varlist or {}
prj._gmake.varlistlength = prj._gmake.varlistlength or 0
local cache = prj._gmake.varlist
local length = prj._gmake.varlistlength
local key = value .. saltValue
if (cache[key] ~= nil) then
return cache[key], false
end
local var = string.format("PERFILE_FLAGS_%d", length)
cache[key] = var
prj._gmake.varlistlength = length + 1
return var, true
end
function cpp.perFileFlags(cfg, fcfg)
local toolset = gmake2.getToolSet(cfg)
local isCFile = path.iscfile(fcfg.name)
local getflags = iif(isCFile, toolset.getcflags, toolset.getcxxflags)
local value = gmake2.list(table.join(getflags(fcfg), fcfg.buildoptions))
if fcfg.defines or fcfg.undefines then
local defs = table.join(toolset.getdefines(fcfg.defines, cfg), toolset.getundefines(fcfg.undefines))
if #defs > 0 then
value = value .. gmake2.list(defs)
end
end
if fcfg.includedirs or fcfg.sysincludedirs or fcfg.frameworkdirs then
local includes = toolset.getincludedirs(cfg, fcfg.includedirs, fcfg.sysincludedirs, fcfg.frameworkdirs)
if #includes > 0 then
value = value .. gmake2.list(includes)
end
end
if #value > 0 then
local newPerFileFlag = false
fcfg.flagsVariable, newPerFileFlag = cpp.makeVarName(cfg.project, value, iif(isCFile, '_C', '_CPP'))
if newPerFileFlag then
if isCFile then
_p('%s = $(ALL_CFLAGS)%s', fcfg.flagsVariable, value)
else
_p('%s = $(ALL_CXXFLAGS)%s', fcfg.flagsVariable, value)
end
end
end
end
function cpp.fileFlags(cfg, file)
local fcfg = fileconfig.getconfig(file, cfg)
local flags = {}
if cfg.pchheader and not cfg.flags.NoPCH and (not fcfg or not fcfg.flags.NoPCH) then
table.insert(flags, "-include $(PCH_PLACEHOLDER)")
end
if fcfg and fcfg.flagsVariable then
table.insert(flags, string.format("$(%s)", fcfg.flagsVariable))
else
local fileExt = cpp.determineFiletype(cfg, file)
if path.iscfile(fileExt) then
table.insert(flags, "$(ALL_CFLAGS)")
elseif path.iscppfile(fileExt) then
table.insert(flags, "$(ALL_CXXFLAGS)")
end
end
return table.concat(flags, ' ')
end
--
-- Write out the file sets.
--
cpp.elements.filesets = function(cfg)
local result = {}
for _, kind in ipairs(cfg._gmake.kinds) do
for _, f in ipairs(cfg._gmake.filesets[kind]) do
table.insert(result, function(cfg, toolset)
cpp.outputFileset(cfg, kind, f)
end)
end
end
return result
end
function cpp.outputFilesSection(prj)
_p('# File sets')
_p('# #############################################')
_p('')
for _, kind in ipairs(prj._gmake.kinds) do
_x('%s :=', kind)
end
_x('')
gmake2.outputSection(prj, cpp.elements.filesets)
end
function cpp.outputFileset(cfg, kind, file)
_x('%s += %s', kind, file)
end
--
-- Write out the targets.
--
cpp.elements.rules = function(cfg)
return {
cpp.allRules,
cpp.targetRules,
gmake2.targetDirRules,
gmake2.objDirRules,
cpp.cleanRules,
gmake2.preBuildRules,
cpp.customDeps,
cpp.pchRules,
}
end
function cpp.outputRulesSection(prj)
_p('# Rules')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, cpp.elements.rules)
end
function cpp.allRules(cfg, toolset)
if cfg.system == p.MACOSX and cfg.kind == p.WINDOWEDAPP then
_p('all: $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist')
_p('\t@:')
_p('')
_p('$(dir $(TARGETDIR))PkgInfo:')
_p('$(dir $(TARGETDIR))Info.plist:')
else
_p('all: $(TARGET)')
_p('\t@:')
end
_p('')
end
function cpp.targetRules(cfg, toolset)
local targets = ''
for _, kind in ipairs(cfg._gmake.kinds) do
if kind ~= 'OBJECTS' and kind ~= 'RESOURCES' then
targets = targets .. '$(' .. kind .. ') '
end
end
targets = targets .. '$(OBJECTS) $(LDDEPS)'
if cfg._gmake.filesets['RESOURCES'] then
targets = targets .. ' $(RESOURCES)'
end
_p('$(TARGET): %s | $(TARGETDIR)', targets)
_p('\t$(PRELINKCMDS)')
_p('\t@echo Linking %s', cfg.project.name)
_p('\t$(SILENT) $(LINKCMD)')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function cpp.customDeps(cfg, toolset)
for _, kind in ipairs(cfg._gmake.kinds) do
if kind == 'CUSTOM' or kind == 'SOURCES' then
_p('$(%s): | prebuild', kind)
end
end
end
function cpp.cleanRules(cfg, toolset)
_p('clean:')
_p('\t@echo Cleaning %s', cfg.project.name)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) rm -f $(TARGET)')
_p('\t$(SILENT) rm -rf $(GENERATED)')
_p('\t$(SILENT) rm -rf $(OBJDIR)')
_p('else')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(GENERATED)) rmdir /s /q $(subst /,\\\\,$(GENERATED))')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
_p('endif')
_p('')
end
function cpp.pchRules(cfg, toolset)
_p('ifneq (,$(PCH))')
_p('$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)')
_p('$(GCH): $(PCH) | prebuild')
_p('\t@echo $(notdir $<)')
local cmd = iif(p.languages.isc(cfg.language), "$(CC) -x c-header $(ALL_CFLAGS)", "$(CXX) -x c++-header $(ALL_CXXFLAGS)")
_p('\t$(SILENT) %s -o "$@" -MF "$(@:%%.gch=%%.d)" -c "$<"', cmd)
_p('$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)')
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) touch "$@"')
_p('else')
_p('\t$(SILENT) echo $null >> "$@"')
_p('endif')
_p('else')
_p('$(OBJECTS): | prebuild')
_p('endif')
_p('')
end
--
-- Output the file compile targets.
--
cpp.elements.fileRules = function(cfg)
local funcs = {}
for _, fileRule in ipairs(cfg._gmake.fileRules) do
table.insert(funcs, function(cfg, toolset)
cpp.outputFileRules(cfg, fileRule)
end)
end
return funcs
end
function cpp.outputFileRuleSection(prj)
_p('# File Rules')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, cpp.elements.fileRules)
end
function cpp.outputFileRules(cfg, file)
local dependencies = p.esc(file.source)
if file.buildinputs and #file.buildinputs > 0 then
dependencies = dependencies .. " " .. table.concat(p.esc(file.buildinputs), " ")
end
_p('%s: %s', file.buildoutputs[1], dependencies)
if file.buildmessage then
_p('\t@echo %s', file.buildmessage)
end
if file.buildcommands then
local cmds = os.translateCommandsAndPaths(file.buildcommands, cfg.project.basedir, cfg.project.location)
for _, cmd in ipairs(cmds) do
if cfg.bindirs and #cfg.bindirs > 0 then
_p('\t$(SILENT) $(EXE_PATHS) %s', cmd)
else
_p('\t$(SILENT) %s', cmd)
end
end
end
-- TODO: this is a hack with some imperfect side-effects.
-- better solution would be to emit a dummy file for the rule, and then outputs depend on it (must clean up dummy in 'clean')
-- better yet, is to use pattern rules, but we need to detect that all outputs have the same stem
if #file.buildoutputs > 1 then
_p('%s: %s', table.concat({ table.unpack(file.buildoutputs, 2) }, ' '), file.buildoutputs[1])
end
end
---------------------------------------------------------------------------
--
-- Handlers for individual makefile elements
--
---------------------------------------------------------------------------
function cpp.dependencies(prj)
-- include the dependencies, built by GCC (with the -MMD flag)
_p('-include $(OBJECTS:%%.o=%%.d)')
_p('ifneq (,$(PCH))')
_p(' -include $(PCH_PLACEHOLDER).d')
_p('endif')
end

View File

@@ -0,0 +1,317 @@
--
-- gmake2_csharp.lua
-- Generate a C# project makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
gmake2.cs = {}
local cs = gmake2.cs
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
--
-- Add namespace for element definition lists for p.callarray()
--
cs.elements = {}
--
-- Generate a GNU make C++ project makefile, with support for the new platforms API.
--
cs.elements.makefile = function(prj)
return {
gmake2.header,
gmake2.phonyRules,
gmake2.csConfigs,
gmake2.csProjectConfig,
gmake2.csSources,
gmake2.csEmbedFiles,
gmake2.csCopyFiles,
gmake2.csResponseFile,
gmake2.shellType,
gmake2.csAllRules,
gmake2.csTargetRules,
gmake2.targetDirRules,
gmake2.csResponseRules,
gmake2.objDirRules,
gmake2.csCleanRules,
gmake2.preBuildRules,
gmake2.csFileRules,
}
end
--
-- Generate a GNU make C# project makefile, with support for the new platforms API.
--
function cs.generate(prj)
p.eol("\n")
local toolset = p.tools.dotnet
p.callArray(cs.elements.makefile, prj, toolset)
end
--
-- Write out the settings for a particular configuration.
--
cs.elements.configuration = function(cfg)
return {
gmake2.csTools,
gmake2.target,
gmake2.objdir,
gmake2.csFlags,
gmake2.csLinkCmd,
gmake2.preBuildCmds,
gmake2.preLinkCmds,
gmake2.postBuildCmds,
gmake2.settings,
}
end
function gmake2.csConfigs(prj, toolset)
for cfg in project.eachconfig(prj) do
_x('ifeq ($(config),%s)', cfg.shortname)
p.callArray(cs.elements.configuration, cfg, toolset)
_p('endif')
_p('')
end
end
--
-- Given a .resx resource file, builds the path to corresponding .resource
-- file, matching the behavior and naming of Visual Studio.
--
function cs.getresourcefilename(cfg, fname)
if path.getextension(fname) == ".resx" then
local name = cfg.buildtarget.basename .. "."
local dir = path.getdirectory(fname)
if dir ~= "." then
name = name .. path.translate(dir, ".") .. "."
end
return "$(OBJDIR)/" .. p.esc(name .. path.getbasename(fname)) .. ".resources"
else
return fname
end
end
--
-- Iterate and output some selection of the source code files.
--
function cs.listsources(prj, selector)
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
local value = selector(node)
if value then
_x('\t%s \\', value)
end
end
})
end
---------------------------------------------------------------------------
--
-- Handlers for individual makefile elements
--
---------------------------------------------------------------------------
function gmake2.csAllRules(prj, toolset)
_p('all: prebuild $(EMBEDFILES) $(COPYFILES) $(TARGET)')
_p('')
end
function gmake2.csCleanRules(prj, toolset)
--[[
-- porting from 4.x
_p('clean:')
_p('\t@echo Cleaning %s', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_p('\t$(SILENT) rm -f $(TARGETDIR)/%s.* $(COPYFILES)', target.basename)
_p('\t$(SILENT) rm -rf $(OBJDIR)')
_p('else')
_p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', target.name, target.basename)
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
for target, source in pairs(copypairs) do
_p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target)
end
_p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))')
_p('endif')
_p('')
--]]
end
function gmake2.csCopyFiles(prj, toolset)
--[[
-- copied from 4.x; needs more porting
_p('COPYFILES += \\')
for target, source in pairs(cfgpairs[anycfg]) do
_p('\t%s \\', target)
end
for target, source in pairs(copypairs) do
_p('\t%s \\', target)
end
_p('')
--]]
end
function cs.getresponsefilename(prj)
return '$(OBJDIR)/' .. prj.filename .. '.rsp'
end
function gmake2.csResponseFile(prj, toolset)
_x('RESPONSE += ' .. gmake2.cs.getresponsefilename(prj))
end
function gmake2.csResponseRules(prj)
local toolset = p.tools.dotnet
local ext = gmake2.getmakefilename(prj, true)
local makefile = path.getname(p.filename(prj, ext))
local response = gmake2.cs.getresponsefilename(prj)
_p('$(RESPONSE): %s', makefile)
_p('\t@echo Generating response file', prj.name)
_p('ifeq (posix,$(SHELLTYPE))')
_x('\t$(SILENT) rm -f $(RESPONSE)')
_p('else')
_x('\t$(SILENT) if exist $(RESPONSE) del %s', path.translate(response, '\\'))
_p('endif')
local sep = os.istarget("windows") and "\\" or "/"
local tr = project.getsourcetree(prj)
p.tree.traverse(tr, {
onleaf = function(node, depth)
if toolset.fileinfo(node).action == "Compile" then
_x('\t@echo %s >> $(RESPONSE)', path.translate(node.relpath, sep))
end
end
})
_p('')
end
function gmake2.csEmbedFiles(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('EMBEDFILES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "EmbeddedResource" then
return cs.getresourcefilename(cfg, node.relpath)
end
end)
_p('')
end
function gmake2.csFileRules(prj, toolset)
--[[
-- porting from 4.x
_p('# Per-configuration copied file rules')
for cfg in p.eachconfig(prj) do
_x('ifneq (,$(findstring %s,$(config)))', cfg.name:lower())
for target, source in pairs(cfgpairs[cfg]) do
p.make_copyrule(source, target)
end
_p('endif')
_p('')
end
_p('# Copied file rules')
for target, source in pairs(copypairs) do
p.make_copyrule(source, target)
end
_p('# Embedded file rules')
for _, fname in ipairs(embedded) do
if path.getextension(fname) == ".resx" then
_x('%s: %s', getresourcefilename(prj, fname), fname)
_p('\t$(SILENT) $(RESGEN) $^ $@')
end
_p('')
end
--]]
end
function gmake2.csFlags(cfg, toolset)
_p(' FLAGS =%s', gmake2.list(toolset.getflags(cfg)))
end
function gmake2.csLinkCmd(cfg, toolset)
local deps = p.esc(config.getlinks(cfg, "dependencies", "fullpath"))
_p(' DEPENDS =%s', gmake2.list(deps))
_p(' REFERENCES = %s', table.implode(deps, "/r:", "", " "))
end
function gmake2.csProjectConfig(prj, toolset)
-- To maintain compatibility with Visual Studio, these values must
-- be set on the project level, and not per-configuration.
local cfg = project.getfirstconfig(prj)
local kindflag = "/t:" .. toolset.getkind(cfg):lower()
local libdirs = table.implode(p.esc(cfg.libdirs), "/lib:", "", " ")
_p('FLAGS += %s', table.concat(table.join(kindflag, libdirs), " "))
local refs = p.esc(config.getlinks(cfg, "system", "fullpath"))
_p('REFERENCES += %s', table.implode(refs, "/r:", "", " "))
_p('')
end
function gmake2.csSources(prj, toolset)
local cfg = project.getfirstconfig(prj)
_p('SOURCES += \\')
cs.listsources(prj, function(node)
local fcfg = fileconfig.getconfig(node, cfg)
local info = toolset.fileinfo(fcfg)
if info.action == "Compile" then
return node.relpath
end
end)
_p('')
end
function gmake2.csTargetRules(prj, toolset)
_p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(RESPONSE) | $(TARGETDIR)')
_p('\t$(PRELINKCMDS)')
_p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) @$(RESPONSE) $(patsubst %%,/resource:%%,$(EMBEDFILES))')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function gmake2.csTools(cfg, toolset)
_p(' CSC = %s', toolset.gettoolname(cfg, "csc"))
_p(' RESGEN = %s', toolset.gettoolname(cfg, "resgen"))
end

View File

@@ -0,0 +1,111 @@
--
-- gmake2_makefile.lua
-- Generate a C/C++ project makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
gmake2.makefile = {}
local makefile = gmake2.makefile
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for p.callArray()
---
makefile.elements = {}
--
-- Generate a GNU make makefile project makefile.
--
makefile.elements.makefile = function(prj)
return {
gmake2.header,
gmake2.phonyRules,
makefile.configs,
makefile.targetRules
}
end
function makefile.generate(prj)
p.eol("\n")
p.callArray(makefile.elements.makefile, prj)
end
makefile.elements.configuration = function(cfg)
return {
gmake2.target,
gmake2.buildCommands,
gmake2.cleanCommands,
}
end
function makefile.configs(prj)
local first = true
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[cfg.toolset or "gcc"]
if not toolset then
error("Invalid toolset '" .. cfg.toolset .. "'")
end
if first then
_x('ifeq ($(config),%s)', cfg.shortname)
first = false
else
_x('else ifeq ($(config),%s)', cfg.shortname)
end
p.callArray(makefile.elements.configuration, cfg, toolset)
_p('')
end
if not first then
_p('else')
_p(' $(error "invalid configuration $(config)")')
_p('endif')
_p('')
end
end
function makefile.targetRules(prj)
_p('$(TARGET):')
_p('\t$(BUILDCMDS)')
_p('')
_p('clean:')
_p('\t$(CLEANCMDS)')
_p('')
end
function gmake2.buildCommands(cfg)
_p(' define BUILDCMDS')
local steps = cfg.buildcommands
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
_p('\t@echo Running build commands')
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p(' endef')
end
function gmake2.cleanCommands(cfg)
_p(' define CLEANCMDS')
local steps = cfg.cleancommands
if #steps > 0 then
steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location)
_p('\t@echo Running clean commands')
_p('\t%s', table.implode(steps, "", "", "\n\t"))
end
_p(' endef')
end

View File

@@ -0,0 +1,386 @@
--
-- gmake2_utility.lua
-- Generate a C/C++ project makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
gmake2.utility = {}
local utility = gmake2.utility
local project = p.project
local config = p.config
local fileconfig = p.fileconfig
---
-- Add namespace for element definition lists for premake.callarray()
---
utility.elements = {}
--
-- Generate a GNU make utility project makefile
--
utility.elements.makefile = function(prj)
return {
gmake2.header,
gmake2.phonyRules,
gmake2.shellType,
utility.initialize,
utility.createFileTable,
utility.outputConfigurationSection,
utility.outputFilesSection,
utility.outputRulesSection,
utility.outputFileRuleSection,
}
end
function utility.generate(prj)
p.eol("\n")
p.callArray(utility.elements.makefile, prj)
-- allow the garbage collector to clean things up.
for cfg in project.eachconfig(prj) do
cfg._gmake = nil
end
prj._gmake = nil
end
function utility.initialize(prj)
prj._gmake = prj._gmake or {}
prj._gmake.rules = prj.rules
prj._gmake.filesets = { }
end
function utility.createFileTable(prj)
for cfg in project.eachconfig(prj) do
cfg._gmake = cfg._gmake or {}
cfg._gmake.filesets = {}
cfg._gmake.fileRules = {}
local files = table.shallowcopy(prj._.files)
table.foreachi(files, function(node)
utility.addFile(cfg, node, prj)
end)
for _, f in pairs(cfg._gmake.filesets) do
table.sort(f)
end
cfg._gmake.kinds = table.keys(cfg._gmake.filesets)
table.sort(cfg._gmake.kinds)
prj._gmake.kinds = table.join(prj._gmake.kinds or {}, cfg._gmake.kinds)
end
prj._gmake.kinds = table.unique(prj._gmake.kinds)
table.sort(prj._gmake.kinds)
end
function utility.addFile(cfg, node, prj)
local filecfg = fileconfig.getconfig(node, cfg)
if not filecfg or filecfg.flags.ExcludeFromBuild then
return
end
-- skip generated files, since we try to figure it out manually below.
if node.generated then
return
end
-- process custom build commands.
if fileconfig.hasCustomBuildRule(filecfg) then
local env = table.shallowcopy(filecfg.environ)
env.PathVars = {
["file.basename"] = { absolute = false, token = node.basename },
["file.abspath"] = { absolute = true, token = node.abspath },
["file.relpath"] = { absolute = false, token = node.relpath },
["file.name"] = { absolute = false, token = node.name },
["file.path"] = { absolute = true, token = node.path },
}
local shadowContext = p.context.extent(filecfg, env)
local buildoutputs = p.project.getrelative(cfg.project, shadowContext.buildoutputs)
if buildoutputs and #buildoutputs > 0 then
local file = {
buildoutputs = buildoutputs,
source = node.relpath,
buildmessage = shadowContext.buildmessage,
buildcommands = shadowContext.buildcommands,
buildinputs = p.project.getrelative(cfg.project, shadowContext.buildinputs)
}
table.insert(cfg._gmake.fileRules, file)
for _, output in ipairs(buildoutputs) do
utility.addGeneratedFile(cfg, node, output)
end
end
else
utility.addRuleFile(cfg, node)
end
end
function utility.addGeneratedFile(cfg, source, filename)
-- mark that we have generated files.
cfg.project.hasGeneratedFiles = true
-- add generated file to the project.
local files = cfg.project._.files
local node = files[filename]
if not node then
node = fileconfig.new(filename, cfg.project)
files[filename] = node
table.insert(files, node)
end
-- always overwrite the dependency information.
node.dependsOn = source
node.generated = true
-- add to config if not already added.
if not fileconfig.getconfig(node, cfg) then
fileconfig.addconfig(node, cfg)
end
-- add file to the fileset.
local filesets = cfg.project._gmake.filesets
local kind = "CUSTOM"
local fileset = cfg._gmake.filesets[kind] or {}
table.insert(fileset, filename)
cfg._gmake.filesets[kind] = fileset
-- recursively setup rules.
utility.addRuleFile(cfg, node)
end
function utility.addRuleFile(cfg, node)
local rules = cfg.project._gmake.rules
local rule = rules[path.getextension(node.abspath):lower()]
if rule then
local filecfg = fileconfig.getconfig(node, cfg)
local environ = table.shallowcopy(filecfg.environ)
if rule.propertydefinition then
p.rule.prepareEnvironment(rule, environ, cfg)
p.rule.prepareEnvironment(rule, environ, filecfg)
end
local shadowContext = p.context.extent(rule, environ)
local buildoutputs = shadowContext.buildoutputs
local buildmessage = shadowContext.buildmessage
local buildcommands = shadowContext.buildcommands
local buildinputs = shadowContext.buildinputs
buildoutputs = p.project.getrelative(cfg.project, buildoutputs)
if buildoutputs and #buildoutputs > 0 then
local file = {
buildoutputs = buildoutputs,
source = node.relpath,
buildmessage = buildmessage,
buildcommands = buildcommands,
buildinputs = buildinputs
}
table.insert(cfg._gmake.fileRules, file)
for _, output in ipairs(buildoutputs) do
utility.addGeneratedFile(cfg, node, output)
end
end
end
end
--
-- Write out the settings for a particular configuration.
--
utility.elements.configuration = function(cfg)
return {
utility.bindirs,
utility.exepaths,
gmake2.settings,
gmake2.preBuildCmds,
gmake2.preLinkCmds,
gmake2.postBuildCmds,
}
end
function utility.outputConfigurationSection(prj)
_p('# Configurations')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, utility.elements.configuration)
end
function utility.bindirs(cfg, toolset)
local dirs = project.getrelative(cfg.project, cfg.bindirs)
if #dirs > 0 then
p.outln('EXECUTABLE_PATHS = "' .. table.concat(dirs, ":") .. '"')
end
end
function utility.exepaths(cfg, toolset)
local dirs = project.getrelative(cfg.project, cfg.bindirs)
if #dirs > 0 then
p.outln('EXE_PATHS = PATH=$(EXECUTABLE_PATHS):$$PATH;')
end
end
--
-- Write out the file sets.
--
utility.elements.filesets = function(cfg)
local result = {}
for _, kind in ipairs(cfg._gmake.kinds) do
for _, f in ipairs(cfg._gmake.filesets[kind]) do
table.insert(result, function(cfg, toolset)
utility.outputFileset(cfg, kind, f)
end)
end
end
return result
end
function utility.outputFilesSection(prj)
_p('# File sets')
_p('# #############################################')
_p('')
for _, kind in ipairs(prj._gmake.kinds) do
_x('%s :=', kind)
end
_x('')
gmake2.outputSection(prj, utility.elements.filesets)
end
function utility.outputFileset(cfg, kind, file)
_x('%s += %s', kind, file)
end
--
-- Write out the targets.
--
utility.elements.rules = function(cfg)
return {
utility.allRules,
utility.targetRules,
gmake2.targetDirRules,
utility.cleanRules,
}
end
function utility.outputRulesSection(prj)
_p('# Rules')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, utility.elements.rules)
end
function utility.allRules(cfg, toolset)
local allTargets = 'all: $(TARGETDIR) $(TARGET)'
for _, kind in ipairs(cfg._gmake.kinds) do
allTargets = allTargets .. ' $(' .. kind .. ')'
end
_p(allTargets)
_p('\t@:')
_p('')
end
function utility.targetRules(cfg, toolset)
local targets = ''
for _, kind in ipairs(cfg._gmake.kinds) do
targets = targets .. '$(' .. kind .. ') '
end
_p('$(TARGET): %s', targets)
_p('\t$(PREBUILDCMDS)')
_p('\t$(PRELINKCMDS)')
_p('\t$(POSTBUILDCMDS)')
_p('')
end
function utility.cleanRules(cfg, toolset)
_p('clean:')
_p('\t@echo Cleaning %s', cfg.project.name)
_p('')
end
--
-- Output the file compile targets.
--
utility.elements.fileRules = function(cfg)
local funcs = {}
for _, fileRule in ipairs(cfg._gmake.fileRules) do
table.insert(funcs, function(cfg, toolset)
utility.outputFileRules(cfg, fileRule)
end)
end
return funcs
end
function utility.outputFileRuleSection(prj)
_p('# File Rules')
_p('# #############################################')
_p('')
gmake2.outputSection(prj, utility.elements.fileRules)
end
function utility.outputFileRules(cfg, file)
local outputs = table.concat(file.buildoutputs, ' ')
local dependencies = p.esc(file.source)
if file.buildinputs and #file.buildinputs > 0 then
dependencies = dependencies .. " " .. table.concat(p.esc(file.buildinputs), " ")
end
_p('%s: %s', outputs, dependencies)
if file.buildmessage then
_p('\t@echo %s', file.buildmessage)
end
if file.buildcommands then
local cmds = os.translateCommandsAndPaths(file.buildcommands, cfg.project.basedir, cfg.project.location)
for _, cmd in ipairs(cmds) do
if cfg.bindirs and #cfg.bindirs > 0 then
_p('\t$(SILENT) $(EXE_PATHS) %s', cmd)
else
_p('\t$(SILENT) %s', cmd)
end
end
end
end

View File

@@ -0,0 +1,202 @@
--
-- gmake2_workspace.lua
-- Generate a workspace-level makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local gmake2 = p.modules.gmake2
local tree = p.tree
local project = p.project
--
-- Generate a GNU make "workspace" makefile, with support for the new platforms API.
--
function gmake2.generate_workspace(wks)
p.eol("\n")
gmake2.header(wks)
gmake2.configmap(wks)
gmake2.projects(wks)
gmake2.workspacePhonyRule(wks)
gmake2.groupRules(wks)
gmake2.projectrules(wks)
gmake2.cleanrules(wks)
gmake2.helprule(wks)
end
--
-- Write out the workspace's configuration map, which maps workspace
-- level configurations to the project level equivalents.
--
function gmake2.configmap(wks)
local first = true
for cfg in p.workspace.eachconfig(wks) do
if first then
_p('ifeq ($(config),%s)', cfg.shortname)
first = false
else
_p('else ifeq ($(config),%s)', cfg.shortname)
end
for prj in p.workspace.eachproject(wks) do
local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform)
if prjcfg then
_p(' %s_config = %s', gmake2.tovar(prj.name), prjcfg.shortname)
end
end
_p('')
end
if not first then
_p('else')
_p(' $(error "invalid configuration $(config)")')
_p('endif')
_p('')
end
end
--
-- Write out the rules for the `make clean` action.
--
function gmake2.cleanrules(wks)
_p('clean:')
for prj in p.workspace.eachproject(wks) do
local prjpath = p.filename(prj, gmake2.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
local prjname = path.getname(prjpath)
_x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname)
end
_p('')
end
--
-- Write out the make file help rule and configurations list.
--
function gmake2.helprule(wks)
_p('help:')
_p(1,'@echo "Usage: make [config=name] [target]"')
_p(1,'@echo ""')
_p(1,'@echo "CONFIGURATIONS:"')
for cfg in p.workspace.eachconfig(wks) do
_x(1, '@echo " %s"', cfg.shortname)
end
_p(1,'@echo ""')
_p(1,'@echo "TARGETS:"')
_p(1,'@echo " all (default)"')
_p(1,'@echo " clean"')
for prj in p.workspace.eachproject(wks) do
_p(1,'@echo " %s"', prj.name)
end
_p(1,'@echo ""')
_p(1,'@echo "For more information, see https://github.com/premake/premake-core/wiki"')
end
--
-- Write out the list of projects that comprise the workspace.
--
function gmake2.projects(wks)
_p('PROJECTS := %s', table.concat(p.esc(table.extract(wks.projects, "name")), " "))
_p('')
end
--
-- Write out the workspace PHONY rule
--
function gmake2.workspacePhonyRule(wks)
local groups = {}
local tr = p.workspace.grouptree(wks)
tree.traverse(tr, {
onbranch = function(n)
table.insert(groups, n.path)
end
})
_p('.PHONY: all clean help $(PROJECTS) ' .. table.implode(groups, '', '', ' '))
_p('')
_p('all: $(PROJECTS)')
_p('')
end
--
-- Write out the phony rules representing project groups
--
function gmake2.groupRules(wks)
-- Transform workspace groups into target aggregate
local tr = p.workspace.grouptree(wks)
tree.traverse(tr, {
onbranch = function(n)
local rule = n.path .. ":"
local projectTargets = {}
local groupTargets = {}
for i, c in pairs(n.children)
do
if type(i) == "string"
then
if c.project
then
table.insert(projectTargets, c.name)
else
table.insert(groupTargets, c.path)
end
end
end
if #groupTargets > 0 then
table.sort(groupTargets)
rule = rule .. " " .. table.concat(groupTargets, " ")
end
if #projectTargets > 0 then
table.sort(projectTargets)
rule = rule .. " " .. table.concat(projectTargets, " ")
end
_p(rule)
_p('')
end
})
end
--
-- Write out the rules to build each of the workspace's projects.
--
function gmake2.projectrules(wks)
for prj in p.workspace.eachproject(wks) do
local deps = project.getdependencies(prj)
deps = table.extract(deps, "name")
_p('%s:%s', p.esc(prj.name), gmake2.list(deps))
local cfgvar = gmake2.tovar(prj.name)
_p('ifneq (,$(%s_config))', cfgvar)
_p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar)
local prjpath = p.filename(prj, gmake2.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath))
local prjname = path.getname(prjpath)
_x(1,'@${MAKE} --no-print-directory -C %s -f %s config=$(%s_config)', prjdir, prjname, cfgvar)
_p('endif')
_p('')
end
end

View File

@@ -0,0 +1,16 @@
require ("gmake2")
return {
"test_gmake2_buildcmds.lua",
"test_gmake2_clang.lua",
"test_gmake2_file_rules.lua",
"test_gmake2_flags.lua",
"test_gmake2_ldflags.lua",
"test_gmake2_linking.lua",
"test_gmake2_makefile.lua",
"test_gmake2_objects.lua",
"test_gmake2_pch.lua",
"test_gmake2_perfile_flags.lua",
"test_gmake2_target_rules.lua",
"test_gmake2_tools.lua",
}

View File

@@ -0,0 +1,48 @@
local suite = test.declare("gmake2_buildcommands")
local gmake2 = premake.modules.gmake2
local wks, prj, cfg
function suite.setup()
wks = workspace("MyWorkspace")
configurations { "Debug", "Release" }
prj = test.createProject(wks)
end
local function prepare()
wks = test.getWorkspace(wks)
prj = test.getproject(wks, 1)
cfg = test.getconfig(prj, "Debug")
local toolset = gmake2.getToolSet(cfg)
gmake2.postBuildCmds(cfg, toolset)
end
function suite.postbuildcommands()
targetname "blink"
kind "StaticLib"
language "C++"
postbuildcommands
{
"mkdir lib/www",
"mkdir lib/www"
}
prepare()
test.capture [[
define POSTBUILDCMDS
@echo Running postbuild commands
mkdir lib/www
mkdir lib/www
endef
]]
end

View File

@@ -0,0 +1,46 @@
--
-- test_gmake2_clang.lua
-- Test Clang support in Makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_clang")
local p = premake
local gmake2 = p.modules.gmake2
--
-- Setup
--
local wks, prj
function suite.setup()
wks = test.createWorkspace()
toolset "clang"
prj = p.workspace.getproject(wks, 1)
end
--
-- Make sure that the correct compilers are used.
--
function suite.usesCorrectCompilers()
gmake2.cpp.outputConfigurationSection(prj)
test.capture [[
# Configurations
# #############################################
ifeq ($(origin CC), default)
CC = clang
endif
ifeq ($(origin CXX), default)
CXX = clang++
endif
ifeq ($(origin AR), default)
AR = ar
endif
]]
end

View File

@@ -0,0 +1,379 @@
--
-- test_gmake2_file_rules.lua
-- Validate the makefile source building rules.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_file_rules")
local p = premake
local gmake2 = p.modules.gmake2
--
-- Setup
--
local wks, prj
function suite.setup()
p.escaper(gmake2.esc)
gmake2.cpp.initialize()
rule "TestRule"
display "Test Rule"
fileextension ".rule"
propertydefinition {
name = "TestProperty",
kind = "boolean",
value = false,
switch = "-p"
}
propertydefinition {
name = "TestProperty2",
kind = "boolean",
value = false,
switch = "-p2"
}
propertydefinition {
name = "TestListProperty",
kind = "list"
}
propertydefinition {
name = "TestListPropertyWithSwitch",
kind = "list",
switch = "-S"
}
propertydefinition {
name = "TestListPropertySeparator",
kind = "list",
separator = ","
}
propertydefinition {
name = "TestListPropertySeparatorWithSwitch",
kind = "list",
separator = ",",
switch = "-O"
}
propertydefinition {
name = "TestEnumProperty",
values = { [0] = "V0", [1] = "V1"},
switch = { [0] = "S0", [1] = "S1"},
value = 0
}
buildmessage 'Rule-ing %{file.name}'
buildcommands 'dorule %{TestProperty} %{TestProperty2} %{TestListProperty} %{TestListPropertyWithSwitch} %{TestListPropertySeparator} %{TestListPropertySeparatorWithSwitch} %{TestEnumProperty} "%{file.path}"'
buildoutputs { "%{file.basename}.obj" }
wks = test.createWorkspace()
end
local function prepare()
prj = p.workspace.getproject(wks, 1)
p.oven.bake()
gmake2.cpp.createRuleTable(prj)
gmake2.cpp.createFileTable(prj)
gmake2.cpp.outputFileRuleSection(prj)
end
--
-- Two files with the same base name should have different object files.
--
function suite.uniqueObjNames_onBaseNameCollision()
files { "src/hello.cpp", "src/greetings/hello.cpp" }
prepare()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/hello.o: src/greetings/hello.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/hello1.o: src/hello.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects should been compiled as c
--
function suite.cFilesGetsCompiledWithCCWhileInCppProject()
files { "src/hello.c", "src/test.cpp" }
prepare()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/test.o: src/test.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects can be compiled as C++ with compileas
--
function suite.cFilesGetsCompiledWithCXXWithCompileas()
files { "src/hello.c", "src/test.c" }
filter { "files:src/hello.c" }
compileas "C++"
prepare()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/test.o: src/test.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- C files in C++ projects can be compiled as C++ with 'compileas' on a configuration basis
--
function suite.cFilesGetsCompiledWithCXXWithCompileasDebugOnly()
files { "src/hello.c", "src/test.c" }
filter { "configurations:Debug", "files:src/hello.c" }
compileas "C++"
prepare()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/test.o: src/test.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
ifeq ($(config),debug)
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
else ifeq ($(config),release)
$(OBJDIR)/hello.o: src/hello.c
@echo $(notdir $<)
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
endif
]]
end
--
-- If a custom build rule is supplied, it should be used.
--
function suite.customBuildRule()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
prepare()
test.capture [[
# File Rules
# #############################################
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
else ifeq ($(config),release)
obj/Release/hello.obj: hello.x
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
endif
]]
end
function suite.customBuildRuleWithAdditionalInputs()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
buildinputs { "%{file.path}.inc", "%{file.path}.inc2" }
prepare()
test.capture [[
# File Rules
# #############################################
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x hello.x.inc hello.x.inc2
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
else ifeq ($(config),release)
obj/Release/hello.obj: hello.x hello.x.inc hello.x.inc2
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
endif
]]
end
function suite.customBuildRuleWithAdditionalOutputs()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj", "%{cfg.objdir}/%{file.basename}.other", "%{cfg.objdir}/%{file.basename}.another" }
prepare()
test.capture [[
# File Rules
# #############################################
ifeq ($(config),debug)
obj/Debug/hello.obj: hello.x
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Debug/hello.xo"
$(SILENT) c2o -c "obj/Debug/hello.xo" -o "obj/Debug/hello.obj"
obj/Debug/hello.other obj/Debug/hello.another: obj/Debug/hello.obj
else ifeq ($(config),release)
obj/Release/hello.obj: hello.x
@echo Compiling hello.x
$(SILENT) cxc -c "hello.x" -o "obj/Release/hello.xo"
$(SILENT) c2o -c "obj/Release/hello.xo" -o "obj/Release/hello.obj"
obj/Release/hello.other obj/Release/hello.another: obj/Release/hello.obj
endif
]]
end
function suite.customRuleWithProps()
rules { "TestRule" }
files { "test.rule", "test2.rule" }
testRuleVars {
TestProperty = true
}
filter "files:test2.rule"
testRuleVars {
TestProperty2 = true
}
prepare()
test.capture [[
# File Rules
# #############################################
test.obj: test.rule
@echo Rule-ing test.rule
$(SILENT) dorule -p "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
$(SILENT) dorule -p -p2 "test2.rule"
]]
end
function suite.propertydefinitionSeparator()
rules { "TestRule" }
files { "test.rule", "test2.rule", "test3.rule", "test4.rule" }
filter "files:test.rule"
testRuleVars {
TestListProperty = { "testValue1", "testValue2" }
}
filter "files:test2.rule"
testRuleVars {
TestListPropertyWithSwitch = { "testValue1", "testValue2" }
}
filter "files:test3.rule"
testRuleVars {
TestListPropertySeparator = { "testValue1", "testValue2" }
}
filter "files:test4.rule"
testRuleVars {
TestListPropertySeparatorWithSwitch = { "testValue1", "testValue2" }
}
prepare()
test.capture [[
# File Rules
# #############################################
test.obj: test.rule
@echo Rule-ing test.rule
$(SILENT) dorule testValue1\ testValue2 "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
$(SILENT) dorule -StestValue1\ -StestValue2 "test2.rule"
test3.obj: test3.rule
@echo Rule-ing test3.rule
$(SILENT) dorule testValue1,testValue2 "test3.rule"
test4.obj: test4.rule
@echo Rule-ing test4.rule
$(SILENT) dorule -OtestValue1,testValue2 "test4.rule"
]]
end
function suite.customRuleWithPropertyDefinitionEnum()
rules { "TestRule" }
files { "test.rule", "test2.rule" }
testRuleVars {
TestEnumProperty = "V0"
}
filter "files:test2.rule"
testRuleVars {
TestEnumProperty = "V1"
}
prepare()
test.capture [[
# File Rules
# #############################################
test.obj: test.rule
@echo Rule-ing test.rule
$(SILENT) dorule S0 "test.rule"
test2.obj: test2.rule
@echo Rule-ing test2.rule
$(SILENT) dorule S1 "test2.rule"
]]
end

View File

@@ -0,0 +1,145 @@
--
-- test_gmake2_flags.lua
-- Tests compiler and linker flags for Makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_flags")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
p.callarray(gmake2.cpp, calls, cfg, toolset)
end
--
-- Include directories should be relative and space separated.
--
function suite.includeDirs()
includedirs { "src/include", "../include" }
prepare { "includes" }
test.capture [[
INCLUDES += -Isrc/include -I../include
]]
end
--
-- symbols "on" should produce -g
--
function suite.symbols_on()
symbols "on"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
--
-- symbols default to 'off'
--
function suite.symbols_default()
symbols "default"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end
--
-- symbols "off" should not produce -g
--
function suite.symbols_off()
symbols "off"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end
--
-- All other symbols flags also produce -g
--
function suite.symbols_fastlink()
symbols "FastLink"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
function suite.symbols_full()
symbols "full"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
--
-- symbols "on" with a proper debugformat should produce a corresponding -g
--
function suite.symbols_on_default()
symbols "on"
debugformat "Default"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g
]]
end
function suite.symbols_on_dwarf()
symbols "on"
debugformat "Dwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -gdwarf
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -gdwarf
]]
end
function suite.symbols_on_split_dwarf()
symbols "on"
debugformat "SplitDwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -gsplit-dwarf
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -gsplit-dwarf
]]
end
--
-- symbols "off" with a proper debugformat should not produce -g
--
function suite.symbols_off_dwarf()
symbols "off"
debugformat "Dwarf"
prepare { "cFlags", "cxxFlags" }
test.capture [[
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS)
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS)
]]
end

View File

@@ -0,0 +1,79 @@
--
-- test_gmake2_ldflags.lua
-- Tests compiler and linker flags for Makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_ldflags")
local p = premake
local gmake2 = p.modules.gmake2
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
symbols "On"
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
gmake2.cpp.ldFlags(cfg, toolset)
end
--
-- Check the output from default project values.
--
function suite.checkDefaultValues()
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS)
]]
end
--
-- Check addition of library search directores.
--
function suite.checkLibDirs()
libdirs { "../libs", "libs" }
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L../libs -Llibs
]]
end
function suite.checkLibDirs_X86_64()
architecture ("x86_64")
system (p.LINUX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
]]
end
function suite.checkLibDirs_X86()
architecture ("x86")
system (p.LINUX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
]]
end
function suite.checkLibDirs_X86_64_MacOSX()
architecture ("x86_64")
system (p.MACOSX)
prepare()
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -m64
]]
end

View File

@@ -0,0 +1,272 @@
--
-- test_gmake2_linking.lua
-- Validate the link step generation for makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_linking")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup and teardown
--
local wks, prj
function suite.setup()
_OS = "linux"
wks, prj = test.createWorkspace()
end
local function prepare(calls)
local cfg = test.getconfig(prj, "Debug")
local toolset = p.tools.gcc
p.callarray(gmake2.cpp, calls, cfg, toolset)
end
--
-- Check link command for a shared C++ library.
--
function suite.links_onCppSharedLib()
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -shared -Wl,-soname=libMyProject.so -s
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
function suite.links_onMacOSXCppSharedLib()
_OS = "macosx"
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -dynamiclib -Wl,-install_name,@rpath/libMyProject.dylib -Wl,-x
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
--
-- Check link command for a shared C library.
--
function suite.links_onCSharedLib()
language "C"
kind "SharedLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -shared -Wl,-soname=libMyProject.so -s
LINKCMD = $(CC) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
]]
end
--
-- Check link command for a static library.
--
function suite.links_onStaticLib()
kind "StaticLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LINKCMD = $(AR) -rcs "$@" $(OBJECTS)
]]
end
--
-- Check link command for the Utility kind.
--
-- Utility projects should only run custom commands, and perform no linking.
--
function suite.links_onUtility()
kind "Utility"
prepare { "linkCmd" }
test.capture [[
LINKCMD =
]]
end
--
-- Check link command for a Mac OS X universal static library.
--
function suite.links_onMacUniversalStaticLib()
architecture "universal"
kind "StaticLib"
prepare { "ldFlags", "linkCmd" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LINKCMD = libtool -o "$@" $(OBJECTS)
]]
end
--
-- Check a linking to a sibling static library.
--
function suite.links_onSiblingStaticLib()
links "MyProject2"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += build/bin/Debug/libMyProject2.a
LDDEPS += build/bin/Debug/libMyProject2.a
]]
end
--
-- Check a linking to a sibling shared library.
--
function suite.links_onSiblingSharedLib()
links "MyProject2"
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Wl,-rpath,'$$ORIGIN/../../build/bin/Debug' -s
LIBS += build/bin/Debug/libMyProject2.so
LDDEPS += build/bin/Debug/libMyProject2.so
]]
end
--
-- Check a linking to a sibling shared library using -l and -L.
--
function suite.links_onSiblingSharedLibRelativeLinks()
links "MyProject2"
flags { "RelativeLinks" }
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'$$ORIGIN/../../build/bin/Debug' -s
LIBS += -lMyProject2
LDDEPS += build/bin/Debug/libMyProject2.so
]]
end
function suite.links_onMacOSXSiblingSharedLib()
_OS = "macosx"
links "MyProject2"
flags { "RelativeLinks" }
test.createproject(wks)
kind "SharedLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'@loader_path/../../build/bin/Debug' -Wl,-x
LIBS += -lMyProject2
LDDEPS += build/bin/Debug/libMyProject2.dylib
]]
end
--
-- Check a linking multiple siblings.
--
function suite.links_onMultipleSiblingStaticLib()
links "MyProject2"
links "MyProject3"
test.createproject(wks)
kind "StaticLib"
location "build"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
LDDEPS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
]]
end
--
-- Check a linking multiple siblings with link groups enabled.
--
function suite.links_onSiblingStaticLibWithLinkGroups()
links "MyProject2"
links "MyProject3"
linkgroups "On"
test.createproject(wks)
kind "StaticLib"
location "build"
test.createproject(wks)
kind "StaticLib"
location "build"
prepare { "ldFlags", "libs", "ldDeps" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -s
LIBS += -Wl,--start-group build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a -Wl,--end-group
LDDEPS += build/bin/Debug/libMyProject2.a build/bin/Debug/libMyProject3.a
]]
end
--
-- When referencing an external library via a path, the directory
-- should be added to the library search paths, and the library
-- itself included via an -l flag.
--
function suite.onExternalLibraryWithPath()
location "MyProject"
links { "libs/SomeLib" }
prepare { "ldFlags", "libs" }
test.capture [[
ALL_LDFLAGS += $(LDFLAGS) -L../libs -s
LIBS += -lSomeLib
]]
end
--
-- When referencing an external library with a period in the
-- file name make sure it appears correctly in the LIBS
-- directive. Currently the period and everything after it
-- is stripped
--
function suite.onExternalLibraryWithPathAndVersion()
location "MyProject"
links { "libs/SomeLib-1.1" }
prepare { "libs", }
test.capture [[
LIBS += -lSomeLib-1.1
]]
end

View File

@@ -0,0 +1,101 @@
--
-- test_gmake2_makefile.lua
-- Validate the makefile projects.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local suite = test.declare("gmake2_makefile")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
kind "Makefile"
end
local function prepare()
prj = test.getproject(wks, 1)
gmake2.makefile.configs(prj)
end
--
-- Check rules for Makefile projects.
--
function suite.makefile_configs_empty()
prepare()
test.capture [[
ifeq ($(config),debug)
TARGETDIR = bin/Debug
TARGET = $(TARGETDIR)/MyProject
define BUILDCMDS
endef
define CLEANCMDS
endef
else ifeq ($(config),release)
TARGETDIR = bin/Release
TARGET = $(TARGETDIR)/MyProject
define BUILDCMDS
endef
define CLEANCMDS
endef
else
$(error "invalid configuration $(config)")
endif
]]
end
function suite.makefile_configs_commands()
buildcommands {
"touch source"
}
cleancommands {
"rm -f source"
}
prepare()
test.capture [[
ifeq ($(config),debug)
TARGETDIR = bin/Debug
TARGET = $(TARGETDIR)/MyProject
define BUILDCMDS
@echo Running build commands
touch source
endef
define CLEANCMDS
@echo Running clean commands
rm -f source
endef
else ifeq ($(config),release)
TARGETDIR = bin/Release
TARGET = $(TARGETDIR)/MyProject
define BUILDCMDS
@echo Running build commands
touch source
endef
define CLEANCMDS
@echo Running clean commands
rm -f source
endef
else
$(error "invalid configuration $(config)")
endif
]]
end

View File

@@ -0,0 +1,474 @@
--
-- test_gmake2_objects.lua
-- Validate the list of objects for a makefile.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_objects")
local p = premake
local gmake2 = p.modules.gmake2
--
-- Setup
--
local wks, prj
function suite.setup()
gmake2.cpp.initialize()
wks = test.createWorkspace()
end
local function prepare()
prj = test.getproject(wks, 1)
gmake2.cpp.createRuleTable(prj)
gmake2.cpp.createFileTable(prj)
gmake2.cpp.outputFilesSection(prj)
end
--
-- If a file is listed at the project level, it should get listed in
-- the project level objects list.
--
function suite.listFileInProjectObjects()
files { "src/hello.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello.o
]]
end
--
-- Only buildable files should be listed.
--
function suite.onlyListBuildableFiles()
files { "include/gl.h", "src/hello.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello.o
]]
end
--
-- A file should only be listed in the configurations to which it belongs.
--
function suite.configFilesAreConditioned()
filter "Debug"
files { "src/hello_debug.cpp" }
filter "Release"
files { "src/hello_release.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
ifeq ($(config),debug)
GENERATED += $(OBJDIR)/hello_debug.o
OBJECTS += $(OBJDIR)/hello_debug.o
else ifeq ($(config),release)
GENERATED += $(OBJDIR)/hello_release.o
OBJECTS += $(OBJDIR)/hello_release.o
endif
]]
end
--
-- Two files with the same base name should have different object files.
--
function suite.uniqueObjNames_onBaseNameCollision()
files { "src/hello.cpp", "src/greetings/hello.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/hello.o
GENERATED += $(OBJDIR)/hello1.o
OBJECTS += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello1.o
]]
end
function suite.uniqueObjNames_onBaseNameCollision2()
files { "a/hello.cpp", "b/hello.cpp", "c/hello1.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/hello.o
GENERATED += $(OBJDIR)/hello1.o
GENERATED += $(OBJDIR)/hello11.o
OBJECTS += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello1.o
OBJECTS += $(OBJDIR)/hello11.o
]]
end
function suite.uniqueObjectNames_onBaseNameCollision_Release()
files { "a/hello.cpp", "b/hello.cpp", "c/hello1.cpp", "d/hello11.cpp" }
filter "configurations:Debug"
excludes {"b/hello.cpp"}
filter "configurations:Release"
excludes {"d/hello11.cpp"}
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/hello.o
GENERATED += $(OBJDIR)/hello11.o
OBJECTS += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello11.o
ifeq ($(config),debug)
GENERATED += $(OBJDIR)/hello111.o
OBJECTS += $(OBJDIR)/hello111.o
else ifeq ($(config),release)
GENERATED += $(OBJDIR)/hello1.o
OBJECTS += $(OBJDIR)/hello1.o
endif
]]
end
--
-- Test that changes in case are treated as if multiple files of the same name are being built
--
function suite.uniqueObjNames_ignoreCase1()
files { "a/hello.cpp", "b/Hello.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/Hello1.o
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/Hello1.o
OBJECTS += $(OBJDIR)/hello.o
]]
end
function suite.uniqueObjNames_ignoreCase2()
files { "a/hello.cpp", "b/hello.cpp", "c/Hello1.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/Hello11.o
GENERATED += $(OBJDIR)/hello.o
GENERATED += $(OBJDIR)/hello1.o
OBJECTS += $(OBJDIR)/Hello11.o
OBJECTS += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello1.o
]]
end
function suite.uniqueObjectNames_ignoreCase_Release()
files { "a/hello.cpp", "b/hello.cpp", "c/Hello1.cpp", "d/Hello11.cpp" }
filter "configurations:Debug"
excludes {"b/hello.cpp"}
filter "configurations:Release"
excludes {"d/Hello11.cpp"}
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
GENERATED += $(OBJDIR)/Hello11.o
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/Hello11.o
OBJECTS += $(OBJDIR)/hello.o
ifeq ($(config),debug)
GENERATED += $(OBJDIR)/Hello111.o
OBJECTS += $(OBJDIR)/Hello111.o
else ifeq ($(config),release)
GENERATED += $(OBJDIR)/hello1.o
OBJECTS += $(OBJDIR)/hello1.o
endif
]]
end
--
-- If there's a custom rule which generate C++ sources build outputs should be placed
-- in separate list so they can be cleaned up properly.
--
function suite.customBuildCommand_generatedCpp()
files { "interface.pkg","source.cpp" }
filter "files:**.pkg"
buildmessage "Binding pkg: %{file.name}"
buildcommands './tolua -o %{file.basename}.cpp -H %{file.basename}.h -n %{file.basename}} %{file.abspath}'
buildoutputs { '%{file.basename}.cpp','%{file.basename}.h' }
prepare()
test.capture [[
# File sets
# #############################################
CUSTOM :=
GENERATED :=
OBJECTS :=
SOURCES :=
CUSTOM += interface.h
GENERATED += $(OBJDIR)/interface.o
GENERATED += $(OBJDIR)/source.o
GENERATED += interface.cpp
GENERATED += interface.h
OBJECTS += $(OBJDIR)/interface.o
OBJECTS += $(OBJDIR)/source.o
SOURCES += interface.cpp
]]
end
--
-- If there's a custom rule for a non-C++ file extension, make sure that those
-- files are included in the build.
--
function suite.customBuildCommand_onCustomFileType()
files { "hello.lua" }
filter "files:**.lua"
buildmessage "Compiling %{file.name}"
buildcommands {
'luac "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.luac"',
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.luac" }
prepare()
test.capture [[
# File sets
# #############################################
CUSTOM :=
GENERATED :=
ifeq ($(config),debug)
CUSTOM += obj/Debug/hello.luac
GENERATED += obj/Debug/hello.luac
else ifeq ($(config),release)
CUSTOM += obj/Release/hello.luac
GENERATED += obj/Release/hello.luac
endif
]]
end
--
-- If a custom rule builds to an object file, include it in the
-- link automatically to match the behavior of Visual Studio
--
function suite.linkBuildOutputs_onNotSpecified()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
ifeq ($(config),debug)
GENERATED += obj/Debug/hello.obj
OBJECTS += obj/Debug/hello.obj
else ifeq ($(config),release)
GENERATED += obj/Release/hello.obj
OBJECTS += obj/Release/hello.obj
endif
]]
end
--
-- Also include it in the link step if we explicitly specified so with
-- linkbuildoutputs.
--
function suite.linkBuildOutputs_onOn()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
linkbuildoutputs "On"
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
ifeq ($(config),debug)
GENERATED += obj/Debug/hello.obj
OBJECTS += obj/Debug/hello.obj
else ifeq ($(config),release)
GENERATED += obj/Release/hello.obj
OBJECTS += obj/Release/hello.obj
endif
]]
end
--
-- If linkbuildoutputs says that we shouldn't include it in the link however,
-- don't do it.
--
function suite.linkBuildOutputs_onOff()
files { "hello.x" }
filter "files:**.x"
buildmessage "Compiling %{file.name}"
buildcommands {
'cxc -c "%{file.path}" -o "%{cfg.objdir}/%{file.basename}.xo"',
'c2o -c "%{cfg.objdir}/%{file.basename}.xo" -o "%{cfg.objdir}/%{file.basename}.obj"'
}
buildoutputs { "%{cfg.objdir}/%{file.basename}.obj" }
linkbuildoutputs "Off"
prepare()
test.capture [[
# File sets
# #############################################
CUSTOM :=
GENERATED :=
ifeq ($(config),debug)
CUSTOM += obj/Debug/hello.obj
GENERATED += obj/Debug/hello.obj
else ifeq ($(config),release)
CUSTOM += obj/Release/hello.obj
GENERATED += obj/Release/hello.obj
endif
]]
end
--
-- If a file is excluded from a configuration, it should not be listed.
--
function suite.excludedFromBuild_onExcludedFile()
files { "hello.cpp" }
filter "Debug"
removefiles { "hello.cpp" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
ifeq ($(config),release)
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello.o
endif
]]
end
function suite.excludedFromBuild_onExcludeFlag()
files { "hello.cpp" }
filter { "Debug", "files:hello.cpp" }
flags { "ExcludeFromBuild" }
prepare()
test.capture [[
# File sets
# #############################################
GENERATED :=
OBJECTS :=
ifeq ($(config),release)
GENERATED += $(OBJDIR)/hello.o
OBJECTS += $(OBJDIR)/hello.o
endif
]]
end

View File

@@ -0,0 +1,224 @@
--
-- test_gmake2_pch.lua
-- Validate the setup for precompiled headers in makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local suite = test.declare("gmake2_pch")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup and teardown
--
local wks, prj
function suite.setup()
os.chdir(_TESTS_DIR)
gmake2.cpp.initialize()
wks, prj = test.createWorkspace()
end
local function prepareVars()
local cfg = test.getconfig(prj, "Debug")
gmake2.cpp.pch(cfg)
end
local function prepareRules()
local cfg = test.getconfig(prj, "Debug")
gmake2.cpp.pchRules(cfg.project)
end
local function prepareFlags()
local project = test.getproject(wks, 1)
gmake2.cpp.createRuleTable(project)
gmake2.cpp.createFileTable(project)
gmake2.cpp.outputFileRuleSection(project)
end
--
-- If no header has been set, nothing should be output.
--
function suite.noConfig_onNoHeaderSet()
prepareVars()
test.isemptycapture()
end
--
-- If a header is set, but the NoPCH flag is also set, then
-- nothing should be output.
--
function suite.noConfig_onHeaderAndNoPCHFlag()
pchheader "include/myproject.h"
flags "NoPCH"
files { 'a.cpp', 'b.cpp' }
prepareFlags()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/a.o: a.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/b.o: b.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
--
-- If a header is specified and the NoPCH flag is not set, then
-- the header can be used.
--
function suite.config_onPchEnabled()
pchheader "include/myproject.h"
prepareVars()
test.capture [[
PCH = include/myproject.h
PCH_PLACEHOLDER = $(OBJDIR)/$(notdir $(PCH))
GCH = $(PCH_PLACEHOLDER).gch
]]
end
--
-- The PCH can be specified relative the an includes search path.
--
function suite.pch_searchesIncludeDirs()
pchheader "premake.h"
includedirs { "../../../src/host" }
prepareVars()
test.capture [[
PCH = ../../../src/host/premake.h
]]
end
--
-- Verify the format of the PCH rules block for a C++ file.
--
function suite.buildRules_onCpp()
pchheader "include/myproject.h"
prepareRules()
test.capture [[
ifneq (,$(PCH))
$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)
$(GCH): $(PCH) | prebuild
@echo $(notdir $<)
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)
ifeq (posix,$(SHELLTYPE))
$(SILENT) touch "$@"
else
$(SILENT) echo $null >> "$@"
endif
else
$(OBJECTS): | prebuild
endif
]]
end
--
-- Verify the format of the PCH rules block for a C file.
--
function suite.buildRules_onC()
language "C"
pchheader "include/myproject.h"
prepareRules()
test.capture [[
ifneq (,$(PCH))
$(OBJECTS): $(GCH) | $(PCH_PLACEHOLDER)
$(GCH): $(PCH) | prebuild
@echo $(notdir $<)
$(SILENT) $(CC) -x c-header $(ALL_CFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
$(PCH_PLACEHOLDER): $(GCH) | $(OBJDIR)
ifeq (posix,$(SHELLTYPE))
$(SILENT) touch "$@"
else
$(SILENT) echo $null >> "$@"
endif
else
$(OBJECTS): | prebuild
endif
]]
end
--
-- If the header is located on one of the include file
-- search directories, it should get found automatically.
--
function suite.findsPCH_onIncludeDirs()
location "MyProject"
pchheader "premake.h"
includedirs { "../../../src/host" }
prepareVars()
test.capture [[
PCH = ../../../../src/host/premake.h
]]
end
--
-- If the header is located on one of the include file
-- search directories, it should get found automatically.
--
function suite.PCHFlag()
pchheader "include/myproject.h"
files { 'a.cpp', 'b.cpp' }
prepareFlags()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/a.o: a.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) -include $(PCH_PLACEHOLDER) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/b.o: b.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) -include $(PCH_PLACEHOLDER) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end
function suite.PCHFlag_PerFile()
pchheader "include/myproject.h"
files { 'a.cpp', 'b.cpp' }
filter { "files:a.cpp" }
flags "NoPCH"
prepareFlags()
test.capture [[
# File Rules
# #############################################
$(OBJDIR)/a.o: a.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
$(OBJDIR)/b.o: b.cpp
@echo $(notdir $<)
$(SILENT) $(CXX) -include $(PCH_PLACEHOLDER) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
]]
end

View File

@@ -0,0 +1,110 @@
--
-- gmake2_perfile_flags.lua
-- Tests compiler and linker flags for Makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_perfile_flags")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup
--
local wks
function suite.setup()
wks = test.createWorkspace()
end
local function prepare()
local prj = p.workspace.getproject(wks, 1)
gmake2.cpp.outputPerFileConfigurationSection(prj)
end
--
-- Test per file settings.
--
function suite.perfile_buildOptions()
files { 'a.cpp', 'b.cpp', 'c.cpp' }
filter { 'files:a.cpp' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387', '-msse3', '-mssse3', '-msse4.1', '-mpclmul' }
filter { 'files:b.cpp' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387' }
filter { 'files:c.cpp' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387', '-msse3', '-mssse3', '-msse4.1', '-maes' }
prepare()
test.capture [[
# Per File Configurations
# #############################################
PERFILE_FLAGS_0 = $(ALL_CXXFLAGS) -msse -msse2 -mfpmath=sse,387 -msse3 -mssse3 -msse4.1 -mpclmul
PERFILE_FLAGS_1 = $(ALL_CXXFLAGS) -msse -msse2 -mfpmath=sse,387
PERFILE_FLAGS_2 = $(ALL_CXXFLAGS) -msse -msse2 -mfpmath=sse,387 -msse3 -mssse3 -msse4.1 -maes
]]
end
function suite.perfile_mixedbuildOptions()
files { 'a.c', 'b.cpp', 'c.c' }
filter { 'files:a.c' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387', '-msse3', '-mssse3', '-msse4.1', '-mpclmul' }
filter { 'files:b.cpp' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387' }
filter { 'files:c.c' }
buildoptions { '-msse', '-msse2', '-mfpmath=sse,387', '-msse3', '-mssse3', '-msse4.1', '-maes' }
prepare()
test.capture [[
# Per File Configurations
# #############################################
PERFILE_FLAGS_0 = $(ALL_CFLAGS) -msse -msse2 -mfpmath=sse,387 -msse3 -mssse3 -msse4.1 -mpclmul
PERFILE_FLAGS_1 = $(ALL_CXXFLAGS) -msse -msse2 -mfpmath=sse,387
PERFILE_FLAGS_2 = $(ALL_CFLAGS) -msse -msse2 -mfpmath=sse,387 -msse3 -mssse3 -msse4.1 -maes
]]
end
function suite.perfile_cxxApi()
files { 'a.cpp', 'b.cpp', 'c.cpp' }
visibility "Hidden"
filter { 'files:b.cpp' }
visibility "Protected"
prepare()
test.capture [[
# Per File Configurations
# #############################################
PERFILE_FLAGS_0 = $(ALL_CXXFLAGS) -fvisibility=protected
]]
end
function suite.perfile_compileas()
files { 'a.c', 'b.cpp' }
filter { 'files:a.c' }
compileas "Objective-C"
filter { 'files:b.cpp' }
compileas "Objective-C++"
prepare()
test.capture [[
# Per File Configurations
# #############################################
PERFILE_FLAGS_0 = $(ALL_CFLAGS) -x objective-c
PERFILE_FLAGS_1 = $(ALL_CXXFLAGS) -x objective-c++
]]
end

View File

@@ -0,0 +1,60 @@
--
-- test_gmake2_target_rules.lua
-- Validate the makefile target building rules.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local p = premake
local suite = test.declare("gmake2_target_rules")
local p = premake
local gmake2 = p.modules.gmake2
local project = p.project
--
-- Setup
--
local wks, prj
function suite.setup()
wks, prj = test.createWorkspace()
end
local function prepare()
local cfg = test.getconfig(prj, "Debug")
gmake2.cpp.allRules(cfg)
end
--
-- Check the default, normal format of the rules.
--
function suite.defaultRules()
prepare()
test.capture [[
all: $(TARGET)
@:
]]
end
--
-- Check rules for an OS X Cocoa application.
--
function suite.osxWindowedAppRules()
system "MacOSX"
kind "WindowedApp"
prepare()
test.capture [[
all: $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist
@:
$(dir $(TARGETDIR))PkgInfo:
$(dir $(TARGETDIR))Info.plist:
]]
end

View File

@@ -0,0 +1,36 @@
--
-- test_gmake2_tools.lua
-- Tests for tools support in makefiles.
-- (c) 2016-2017 Jason Perkins, Blizzard Entertainment and the Premake project
--
local suite = test.declare("gmake2_tools")
local p = premake
local gmake2 = p.modules.gmake2
local project = premake.project
--
-- Setup
--
local cfg
function suite.setup()
local wks, prj = test.createWorkspace()
cfg = test.getconfig(prj, "Debug")
end
--
-- Make sure that the correct tools are used.
--
function suite.usesCorrectTools()
gmake2.cpp.tools(cfg, p.tools.gcc)
test.capture [[
RESCOMP = windres
]]
end

View File

@@ -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.

View File

@@ -0,0 +1,5 @@
return {
"_preload.lua",
"raw.lua",
"raw_action.lua",
}

View File

@@ -0,0 +1,16 @@
newaction
{
trigger = "raw",
shortname = "Raw output",
description = "Generate raw representation of Premake structures",
onsolution = function(sln)
require('raw')
premake.generate(sln, ".raw", premake.raw.workspace)
end,
}
return function(cfg)
return (_ACTION == "raw")
end

View File

@@ -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

View File

@@ -0,0 +1,76 @@
local p = premake
p.raw = { }
local raw = p.raw
local gvisited = { }
function raw.workspace(wks)
if not gvisited[wks.global] then
gvisited[wks.global] = true
raw.printTable({ global = wks.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

View File

@@ -0,0 +1,7 @@
return {
"self-test.lua",
"test_assertions.lua",
"test_declare.lua",
"test_helpers.lua",
"test_runner.lua"
}

View File

@@ -0,0 +1,106 @@
---
-- self-test/self-test.lua
--
-- An automated test framework for Premake and its add-on modules.
--
-- Author Jason Perkins
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
---
local p = premake
p.modules.self_test = {}
local m = p.modules.self_test
m._VERSION = p._VERSION
newaction {
trigger = "self-test",
shortname = "Test Premake",
description = "Run Premake's own local unit test suites",
execute = function()
m.executeSelfTest()
end
}
newoption {
trigger = "test-only",
value = "suite[.test]",
description = "For self-test action; run specific suite or test"
}
function m.executeSelfTest()
m.detectDuplicateTests = true
m.loadTestsFromManifests()
m.detectDuplicateTests = false
local tests = {}
local isAction = true
for i, arg in ipairs(_ARGS) do
local _tests, err = m.getTestsWithIdentifier(arg)
if err then
error(err, 0)
end
tests = table.join(tests, _tests)
end
if #tests == 0 or _OPTIONS["test-only"] ~= nil then
local _tests, err = m.getTestsWithIdentifier(_OPTIONS["test-only"])
if err then
error(err, 0)
end
tests = table.join(tests, _tests)
end
local passed, failed = m.runTest(tests)
if failed > 0 then
printf("\n %d FAILED TEST%s", failed, iif(failed > 1, "S", ""))
os.exit(5)
end
end
function m.loadTestsFromManifests()
local mask = path.join(_MAIN_SCRIPT_DIR, "**/tests/_tests.lua")
local manifests = os.matchfiles(mask)
-- TODO: "**" should also match "." but doesn't currently
local top = path.join(_MAIN_SCRIPT_DIR, "tests/_tests.lua")
if os.isfile(top) then
table.insert(manifests, 1, top)
end
for i = 1, #manifests do
local manifest = manifests[i]
_TESTS_DIR = path.getdirectory(manifest)
local files = dofile(manifest)
for i = 1, #files do
local filename = path.join(_TESTS_DIR, files[i])
dofile(filename)
end
end
end
dofile("test_assertions.lua")
dofile("test_declare.lua")
dofile("test_helpers.lua")
dofile("test_runner.lua")
return m

View File

@@ -0,0 +1,240 @@
---
-- test_assertions.lua
--
-- Assertion functions for unit tests.
--
-- Author Jason Perkins
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
---
local p = premake
local m = p.modules.self_test
local _ = {}
function m.capture(expected)
local actual = p.captured() .. p.eol()
-- create line-by-line iterators for both values
local ait = actual:gmatch("(.-)" .. p.eol())
local eit = expected:gmatch("(.-)\n")
-- compare each value line by line
local linenum = 1
local atxt = ait()
local etxt = eit()
while etxt do
if (etxt ~= atxt) then
m.fail("(%d) expected:\n%s\n...but was:\n%s\nfulltext:\n%s", linenum, etxt, atxt, actual)
end
linenum = linenum + 1
atxt = ait()
etxt = eit()
end
end
function m.closedfile(expected)
if expected and not m.value_closedfile then
m.fail("expected file to be closed")
elseif not expected and m.value_closedfile then
m.fail("expected file to remain open")
end
end
function m.contains(expected, actual)
if type(expected) == "table" then
for i, v in ipairs(expected) do
m.contains(v, actual)
end
elseif not table.contains(actual, expected) then
m.fail("expected value %s not found", expected)
end
end
function m.excludes(expected, actual)
if type(expected) == "table" then
for i, v in ipairs(expected) do
m.excludes(v, actual)
end
elseif table.contains(actual, expected) then
m.fail("excluded value %s found", expected)
end
end
function m.fail(format, ...)
-- if format is a number then it is the stack depth
local depth = 3
local arg = {...}
if type(format) == "number" then
depth = depth + format
format = table.remove(arg, 1)
end
-- convert nils into something more usefuls
for i = 1, #arg do
if (arg[i] == nil) then
arg[i] = "(nil)"
elseif (type(arg[i]) == "table") then
arg[i] = "{" .. table.concat(arg[i], ", ") .. "}"
end
end
local msg = string.format(format, table.unpack(arg))
error(debug.traceback(msg, depth), depth)
end
function m.filecontains(expected, fn)
local f = io.open(fn)
local actual = f:read("*a")
f:close()
if (expected ~= actual) then
m.fail("expected %s but was %s", expected, actual)
end
end
function m.hasoutput()
local actual = p.captured()
if actual == "" then
m.fail("expected output, received none");
end
end
function m.isemptycapture()
local actual = p.captured()
if actual ~= "" then
m.fail("expected empty capture, but was %s", actual);
end
end
function m.isequal(expected, actual, depth)
depth = depth or 0
if type(expected) == "table" then
if expected and not actual then
m.fail(depth, "expected table, got nil")
end
if #expected < #actual then
m.fail(depth, "expected %d items, got %d", #expected, #actual)
end
for k,v in pairs(expected) do
m.isequal(expected[k], actual[k], depth + 1)
end
else
if (expected ~= actual) then
m.fail(depth, "expected %s but was %s", expected, actual or "nil")
end
end
return true
end
function m.isfalse(value)
if (value) then
m.fail("expected false but was true")
end
end
function m.isnil(value)
if (value ~= nil) then
m.fail("expected nil but was " .. tostring(value))
end
end
function m.isnotnil(value)
if (value == nil) then
m.fail("expected not nil")
end
end
function m.issame(expected, action)
if expected ~= action then
m.fail("expected same value")
end
end
function m.istrue(value)
if (not value) then
m.fail("expected true but was false")
end
end
function m.missing(value, actual)
if table.contains(actual, value) then
m.fail("unexpected value %s found", value)
end
end
function m.openedfile(fname)
if fname ~= m.value_openedfilename then
local msg = "expected to open file '" .. fname .. "'"
if m.value_openedfilename then
msg = msg .. ", got '" .. m.value_openedfilename .. "'"
end
m.fail(msg)
end
end
function m.success(fn, ...)
local ok, err = pcall(fn, ...)
if not ok then
m.fail("call failed: " .. err)
end
end
function m.stderr(expected)
if not expected and m.stderr_capture then
m.fail("Unexpected: " .. m.stderr_capture)
elseif expected then
if not m.stderr_capture or not m.stderr_capture:find(expected) then
m.fail(string.format("expected '%s'; got %s", expected, m.stderr_capture or "(nil)"))
end
end
end
function m.notstderr(expected)
if not expected and not m.stderr_capture then
m.fail("Expected output on stderr; none received")
elseif expected then
if m.stderr_capture and m.stderr_capture:find(expected) then
m.fail(string.format("stderr contains '%s'; was %s", expected, m.stderr_capture))
end
end
end

Some files were not shown because too many files have changed in this diff Show More