Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/premake-4.x.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstarkos <unknown>2008-12-15 18:00:35 +0300
committerstarkos <unknown>2008-12-15 18:00:35 +0300
commitb57df3a428069f854bf388a5e4181806fe7a92e7 (patch)
treeac34f2207f0e11b89165c702bba12a7d47901583
parent548cf91fd5121890592928c8a1da4bcf954d7e14 (diff)
** Merged GMake C# support from branches/csharp (r630:648)
-rw-r--r--samples/project/CsConsoleApp/App.config0
-rw-r--r--samples/project/CsConsoleApp/Crate.bmpbin0 -> 66614 bytes
-rw-r--r--samples/project/CsConsoleApp/CsConsoleApp.cs21
-rw-r--r--samples/project/CsConsoleApp/Resources.resx123
-rw-r--r--samples/project/CsConsoleApp/premake4.lua12
-rw-r--r--samples/project/CsSharedLib/CsSharedLib.cs9
-rw-r--r--samples/project/CsSharedLib/premake4.lua11
-rw-r--r--samples/project/premake43
-rw-r--r--samples/project/premake4.lua5
-rw-r--r--src/_manifest.lua8
-rw-r--r--src/_premake_main.lua55
-rw-r--r--src/actions/clean/_clean.lua9
-rw-r--r--src/actions/make/make_cpp.tmpl25
-rw-r--r--src/actions/make/make_csharp.tmpl216
-rw-r--r--src/base/api.lua (renamed from src/base/functions.lua)183
-rw-r--r--src/base/config.lua415
-rw-r--r--src/base/configs.lua305
-rw-r--r--src/base/os.lua13
-rw-r--r--src/base/premake.lua196
-rw-r--r--src/base/project.lua432
-rw-r--r--src/base/table.lua10
-rw-r--r--src/base/template.lua18
-rw-r--r--src/base/validate.lua115
-rw-r--r--src/tools/csc.lua35
-rw-r--r--tests/premake4.lua2
-rw-r--r--tests/test_api.lua116
-rw-r--r--tests/test_path.lua4
-rw-r--r--tests/test_project.lua198
-rw-r--r--tests/test_targets.lua4
29 files changed, 1474 insertions, 1069 deletions
diff --git a/samples/project/CsConsoleApp/App.config b/samples/project/CsConsoleApp/App.config
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/project/CsConsoleApp/App.config
diff --git a/samples/project/CsConsoleApp/Crate.bmp b/samples/project/CsConsoleApp/Crate.bmp
new file mode 100644
index 0000000..73fe985
--- /dev/null
+++ b/samples/project/CsConsoleApp/Crate.bmp
Binary files differ
diff --git a/samples/project/CsConsoleApp/CsConsoleApp.cs b/samples/project/CsConsoleApp/CsConsoleApp.cs
new file mode 100644
index 0000000..65786ca
--- /dev/null
+++ b/samples/project/CsConsoleApp/CsConsoleApp.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Reflection;
+using System.Resources;
+
+public class CsConsoleApp
+{
+ static int Main()
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ ResourceManager resx = new ResourceManager("CsConsoleApp.Resources", assembly);
+ string greeting = resx.GetString("Greeting");
+ Console.WriteLine(greeting);
+
+ Console.WriteLine("CsConsoleApp");
+
+ CsSharedLib lib = new CsSharedLib();
+ lib.DoIt();
+
+ return 0;
+ }
+}
diff --git a/samples/project/CsConsoleApp/Resources.resx b/samples/project/CsConsoleApp/Resources.resx
new file mode 100644
index 0000000..518cff0
--- /dev/null
+++ b/samples/project/CsConsoleApp/Resources.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="Greeting" xml:space="preserve">
+ <value>Hi there!</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/samples/project/CsConsoleApp/premake4.lua b/samples/project/CsConsoleApp/premake4.lua
new file mode 100644
index 0000000..e3e6c01
--- /dev/null
+++ b/samples/project/CsConsoleApp/premake4.lua
@@ -0,0 +1,12 @@
+project "CsConsoleApp"
+
+ kind "ConsoleApp"
+ language "C#"
+
+ files { "*.cs", "*.bmp", "App.config", "Resources.resx" }
+
+ libdirs { "../lib" }
+ links { "CsSharedLib", "CppSharedLib", "System" }
+
+ configuration "Crate.bmp"
+ buildaction "Embed"
diff --git a/samples/project/CsSharedLib/CsSharedLib.cs b/samples/project/CsSharedLib/CsSharedLib.cs
new file mode 100644
index 0000000..1c68e0f
--- /dev/null
+++ b/samples/project/CsSharedLib/CsSharedLib.cs
@@ -0,0 +1,9 @@
+using System;
+
+public class CsSharedLib
+{
+ public void DoIt()
+ {
+ Console.WriteLine("CsSharedLib");
+ }
+}
diff --git a/samples/project/CsSharedLib/premake4.lua b/samples/project/CsSharedLib/premake4.lua
new file mode 100644
index 0000000..e8df542
--- /dev/null
+++ b/samples/project/CsSharedLib/premake4.lua
@@ -0,0 +1,11 @@
+project "CsSharedLib"
+
+ kind "SharedLib"
+ language "C#"
+ files { "*.cs" }
+
+ configuration "Debug"
+ targetdir "lib/debug"
+
+ configuration "Release"
+ targetdir "lib/release"
diff --git a/samples/project/premake4 b/samples/project/premake4
index 2c6c4a3..872817e 100644
--- a/samples/project/premake4
+++ b/samples/project/premake4
@@ -1,2 +1,3 @@
#!/bin/sh
-../../bin/debug/premake4 /scripts=../../src $1 $2 $3 $4 $5 $6
+
+../../bin/debug/premake4 /scripts=../../src $1 $2 $3 $4 $5 $6 $7
diff --git a/samples/project/premake4.lua b/samples/project/premake4.lua
index b5a1788..b39956b 100644
--- a/samples/project/premake4.lua
+++ b/samples/project/premake4.lua
@@ -1,8 +1,6 @@
solution "PremakeTestbox"
configurations { "Debug", "Release" }
- location "build"
-
configuration "Debug"
targetdir "bin/debug"
flags { "Symbols" }
@@ -15,13 +13,16 @@ solution "PremakeTestbox"
include "CppConsoleApp"
+include "CsConsoleApp"
include "CppWindowedApp"
include "CppSharedLib"
+include "CsSharedLib"
include "CppStaticLib"
function onclean()
os.rmdir("bin")
os.rmdir("CppSharedLib/lib")
os.rmdir("CppStaticLib/lib")
+ os.rmdir("CsSharedLib/lib")
end
diff --git a/src/_manifest.lua b/src/_manifest.lua
index 7026bd6..744f307 100644
--- a/src/_manifest.lua
+++ b/src/_manifest.lua
@@ -10,20 +10,20 @@
local scripts =
{
+ "base/os.lua",
"base/path.lua",
"base/string.lua",
"base/table.lua",
- "base/os.lua",
"base/globals.lua",
- "base/premake.lua",
"base/template.lua",
"base/project.lua",
- "base/config.lua",
- "base/functions.lua",
+ "base/configs.lua",
+ "base/api.lua",
"base/cmdline.lua",
"tools/csc.lua",
"tools/gcc.lua",
"tools/ow.lua",
+ "base/validate.lua",
"base/help.lua",
}
diff --git a/src/_premake_main.lua b/src/_premake_main.lua
index bfcdd0e..3216dda 100644
--- a/src/_premake_main.lua
+++ b/src/_premake_main.lua
@@ -12,6 +12,52 @@
--
+-- Fire a particular action. Generates the output files from the templates
+-- listed in the action descriptor, and calls any registered handler functions.
+--
+
+ local function doaction(name)
+ local action = premake.actions[name]
+
+ -- walk the session objects and generate files from the templates
+ local function generatefiles(this, templates)
+ if (not templates) then return end
+ for _,tmpl in ipairs(templates) do
+ local output = true
+ if (tmpl[3]) then
+ output = tmpl[3](this)
+ end
+ if (output) then
+ local fname = premake.getoutputname(this, tmpl[1])
+ local f, err = io.open(fname, "wb")
+ if (not f) then
+ error(err, 0)
+ end
+ io.output(f)
+
+ -- call the template function to generate the output
+ tmpl[2](this)
+
+ io.output():close()
+ end
+ end
+ end
+
+ for _,sln in ipairs(_SOLUTIONS) do
+ generatefiles(sln, action.solutiontemplates)
+ for prj in premake.eachproject(sln) do
+ generatefiles(prj, action.projecttemplates)
+ end
+ end
+
+ if (action.execute) then
+ action.execute()
+ end
+ end
+
+
+
+--
-- Script-side program entry point.
--
@@ -95,12 +141,19 @@
ok, err = premake.checktools()
if (not ok) then error("Error: " .. err, 0) end
+ -- work-in-progress: build the configurations
+ print("Building configurations...")
+ premake.buildconfigs()
+
ok, err = premake.checkprojects()
if (not ok) then error("Error: " .. err, 0) end
-- Hand over control to the action
- premake.doaction(_ACTION)
+ printf("Running action '%s'...", _ACTION)
+ doaction(_ACTION)
+
+ print("Done.")
return 0
end
diff --git a/src/actions/clean/_clean.lua b/src/actions/clean/_clean.lua
index 0b6b327..107e064 100644
--- a/src/actions/clean/_clean.lua
+++ b/src/actions/clean/_clean.lua
@@ -42,12 +42,12 @@
-- and delete any toolset agnostic files along the way.
for _,sln in ipairs(_SOLUTIONS) do
table.insert(solutions, path.join(sln.location, sln.name))
-
+
for prj in premake.eachproject(sln) do
table.insert(projects, path.join(prj.location, prj.name))
- if (prj.objdir) then
- os.rmdir(rebase(prj, prj.objdir))
+ if (prj.objectsdir) then
+ os.rmdir(rebase(prj, prj.objectsdir))
end
for cfg in premake.eachconfig(prj) do
@@ -65,7 +65,7 @@
os.remove(rebase(cfg, premake.gettarget(cfg, "link", "windows").fullpath))
os.remove(rebase(cfg, premake.gettarget(cfg, "link", "linux").fullpath))
- os.rmdir(rebase(cfg, cfg.objdir))
+ os.rmdir(rebase(cfg, cfg.objectsdir))
end
end
end
@@ -88,5 +88,6 @@
if (type(onclean) == "function") then
onclean()
end
+
end,
}
diff --git a/src/actions/make/make_cpp.tmpl b/src/actions/make/make_cpp.tmpl
index 73556c1..0ab9067 100644
--- a/src/actions/make/make_cpp.tmpl
+++ b/src/actions/make/make_cpp.tmpl
@@ -68,16 +68,17 @@ ifeq (/bin,$(findstring /bin,$(SHELL)))
endif
ifeq (posix,$(SHELLTYPE))
- MKDIR := mkdir -p
- PATHSEP := /
+ define MKDIR_RULE
+ @echo Creating $@
+ @mkdir -p $@
+ endef
else
- MKDIR := mkdir
- PATHSEP := \\
+ define MKDIR_RULE
+ @echo Creating $@
+ @mkdir $(subst /,\\,$@)
+ endef
endif
-SYS_TARGET := $(subst /,$(PATHSEP),$(TARGET))
-SYS_TARGETDIR := $(subst /,$(PATHSEP),$(TARGETDIR))
-SYS_OBJDIR := $(subst /,$(PATHSEP),$(OBJDIR))
.PHONY: clean prebuild prelink
@@ -95,12 +96,10 @@ $(TARGET): $(TARGETDIR) $(OBJDIR) prebuild $(OBJECTS) $(LDDEPS) $(RESOURCES) pre
$(POSTBUILDCMDS)
$(TARGETDIR):
- @echo Creating $@
- @$(MKDIR) $(SYS_TARGETDIR)
+ $(MKDIR_RULE)
$(OBJDIR):
- @echo Creating $@
- @$(MKDIR) $(SYS_OBJDIR)
+ $(MKDIR_RULE)
clean:
@echo Cleaning <%= this.name %>
@@ -108,8 +107,8 @@ ifeq (posix,$(SHELLTYPE))
@rm -f $(TARGET)
@rm -rf $(OBJDIR)
else
- @if exist $(SYS_TARGET) del $(SYS_TARGET)
- @if exist $(SYS_OBJDIR) rmdir /s /q $(SYS_OBJDIR)
+ @if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
+ @if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
endif
prebuild:
diff --git a/src/actions/make/make_csharp.tmpl b/src/actions/make/make_csharp.tmpl
index 5fe19b6..e5134d7 100644
--- a/src/actions/make/make_csharp.tmpl
+++ b/src/actions/make/make_csharp.tmpl
@@ -1,4 +1,76 @@
-<% local csc = premake.csc %>
+<%
+ local csc = premake.csc
+
+ --
+ -- Given a .resx resource file, builds the path to corresponding .resource
+ -- file, matching the behavior and naming of Visual Studio.
+ --
+
+ function 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)/" .. name .. path.getbasename(fname) .. ".resources"
+ else
+ return fname
+ end
+ end
+
+
+ -- Do some processing up front: build a list of configuration-dependent libraries.
+ -- Libraries that are built to a location other than $(TARGETDIR) will need to
+ -- be copied so they can be found at runtime.
+ local cfglibs = { }
+ local cfgpairs = { }
+ local anycfg
+ for cfg in premake.eachconfig(this) do
+ anycfg = cfg
+ cfglibs[cfg] = premake.getlinks(cfg, "siblings", "fullpath")
+ cfgpairs[cfg] = { }
+ for _, fname in ipairs(cfglibs[cfg]) do
+ if path.getdirectory(fname) ~= cfg.buildtarget.directory then
+ cfgpairs[cfg]["$(TARGETDIR)/"..path.getname(fname)] = fname
+ end
+ end
+ end
+
+ -- sort the files into categories, based on their build action
+ local sources = {}
+ local embedded = { }
+ local copypairs = { }
+
+ for fcfg in premake.eachfile(this) do
+ local action = fcfg.buildaction or csc.getbuildaction(fcfg.name)
+ if action == "Compile" then
+ table.insert(sources, fcfg.name)
+ elseif action == "Embed" then
+ table.insert(embedded, fcfg.name)
+ elseif action == "Copy" then
+ copypairs["$(TARGETDIR)/"..path.getname(fcfg.name)] = fcfg.name
+ elseif path.getname(fcfg.name):lower() == "app.config" then
+ copypairs["$(TARGET).config"] = fcfg.name
+ end
+ end
+
+ -- Any assemblies that are on the library search paths should be copied
+ -- to $(TARGETDIR) so they can be found at runtime
+ local paths = table.translate(this.libdirs, function(v) return path.join(this.basedir, v) end)
+ paths = table.join({this.basedir}, paths)
+ for _, libname in ipairs(premake.getlinks(this, "system", "fullpath")) do
+ local libdir = os.pathsearch(libname..".dll", unpack(paths))
+ if (libdir) then
+ local target = "$(TARGETDIR)/"..path.getname(libname)
+ local source = path.getrelative(this.basedir, path.join(libdir, libname))..".dll"
+ copypairs[target] = source
+ end
+ end
+
+ -- end of preprocessing --
+
+%>
# <%= premake.actions[_ACTION].shortname %> project makefile autogenerated by Premake
ifndef CONFIG
@@ -13,21 +85,143 @@ ifndef RESGEN
RESGEN=resgen
endif
-
<% for cfg in premake.eachconfig(this) do %>
ifeq ($(CONFIG),<%= _MAKE.esc(cfg.name)%>)
- TARGETDIR = <%= _MAKE.esc(cfg.buildtarget.directory) %>
- OBJDIR = <%= _MAKE.esc(cfg.objectsdir) %>
+ TARGETDIR := <%= _MAKE.esc(cfg.buildtarget.directory) %>
+ OBJDIR := <%= _MAKE.esc(cfg.objectsdir) %>
+ DEPENDS := <%= table.concat(_MAKE.esc(premake.getlinks(cfg, "dependencies", "fullpath")), " ") %>
+ REFERENCES := <%= table.implode(_MAKE.esc(cfglibs[cfg]), "/r:", "", "") %>
FLAGS += <%= table.concat(csc.getflags(cfg), " ") %> <%= table.implode(cfg.defines, "/d:", "", " ") %>
- <% local siblings = _MAKE.esc(premake.getlinks(cfg, "siblings", "fullpath")) %>
- REFERENCES += <%= table.implode(siblings, "/r:", "", " ") %>
- DEPENDS += <%= table.concat(siblings, " ") %>
+ define PREBUILDCMDS
+ <% if #cfg.prebuildcommands > 0 then %>
+ @echo Running pre-build commands
+ <%= table.implode(cfg.prebuildcommands, "", "", "\n\t") %>
+ <% end %>
+ endef
+ define PRELINKCMDS
+ <% if #cfg.prelinkcommands > 0 then %>
+ @echo Running pre-link commands
+ <%= table.implode(cfg.prelinkcommands, "", "", "\n\t") %>
+ <% end %>
+ endef
+ define POSTBUILDCMDS
+ <% if #cfg.postbuildcommands > 0 then %>
+ @echo Running post-build commands
+ <%= table.implode(cfg.postbuildcommands, "", "", "\n\t") %>
+ <% end %>
+ endef
endif
+<% end %>
+
+# To maintain compatibility with VS.NET, these values must be set at the project level
+TARGET = $(TARGETDIR)/<%= _MAKE.esc(this.buildtarget.name) %>
+FLAGS += /t:<%= csc.getkind(this) %> <%= table.implode(_MAKE.esc(this.libdirs), "/lib:", "", " ") %>
+REFERENCES += <%= table.implode(_MAKE.esc(premake.getlinks(this, "system", "basename")), "/r:", ".dll", " ") %>
+
+SOURCES := \
+<% for _, fname in ipairs(sources) do %>
+ <%= _MAKE.esc(fname) %> \
<% end %>
-TARGET = $(TARGETDIR)/<%= _MAKE.esc(this.buildtarget.name) %>
-<% if #this.libdirs > 0 then %>
-FLAGS += <%= table.implode(_MAKE.esc(this.libdirs), "/lib:", "", " ") %>
+EMBEDFILES := \
+<% for _, fname in ipairs(embedded) do %>
+ <%= _MAKE.esc(getresourcefilename(this, fname)) %> \
+<% end %>
+
+COPYFILES += \
+<% for target, source in pairs(cfgpairs[anycfg]) do %>
+ <%= _MAKE.esc(target) %> \
+<% end %>
+<% for target, source in pairs(copypairs) do %>
+ <%= _MAKE.esc(target) %> \
+<% end %>
+
+
+SHELLTYPE := msdos
+ifeq (,$(ComSpec)$(COMSPEC))
+ SHELLTYPE := posix
+endif
+ifeq (/bin,$(findstring /bin,$(SHELL)))
+ SHELLTYPE := posix
+endif
+
+ifeq (posix,$(SHELLTYPE))
+ define MKDIR_RULE
+ @echo Creating $@
+ @mkdir -p $@
+ endef
+ define COPY_RULE
+ @echo Copying $(notdir $@)
+ @cp -fR $^ $@
+ endef
+else
+ define MKDIR_RULE
+ @echo Creating $@
+ @mkdir $(subst /,\\,$@)
+ endef
+ define COPY_RULE
+ @echo Copying $(notdir $@)
+ @copy /Y $(subst /,\\,$^) $(subst /,\\,$@)
+ endef
+endif
+
+
+.PHONY: clean prebuild prelink
+
+all: $(TARGET) $(COPYFILES)
+
+$(TARGET): $(TARGETDIR) $(OBJDIR) prebuild $(SOURCES) $(EMBEDFILES) $(DEPENDS) prelink
+ @$(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) $(SOURCES) $(patsubst %,/resource:%,$(EMBEDFILES))
+ $(POSTBUILDCMDS)
+
+$(TARGETDIR):
+ $(MKDIR_RULE)
+
+$(OBJDIR):
+ $(MKDIR_RULE)
+
+clean:
+ @echo Cleaning <%= this.name %>
+ifeq (posix,$(SHELLTYPE))
+ @rm -f $(TARGETDIR)/<%= this.buildtarget.basename %>.* $(COPYFILES)
+ @rm -rf $(OBJDIR)
+else
+ @if exist $(subst /,\\,$(TARGETDIR)/<%= this.buildtarget.basename %>.*) del $(subst /,\\,$(TARGETDIR)/<%= this.buildtarget.basename %>.*)
+ <% for target, source in pairs(cfgpairs[anycfg]) do %>
+ @if exist $(subst /,\\,<%= target %>) del $(subst /,\\,<%= target %>)
+ <% end %>
+ <% for target, source in pairs(copypairs) do %>
+ @if exist $(subst /,\\,<%= target %>) del $(subst /,\\,<%= target %>)
+ <% end %>
+ @if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
+endif
+
+prebuild:
+ $(PREBUILDCMDS)
+
+prelink:
+ $(PRELINKCMDS)
+
+
+# Per-configuration copied file rules
+<% for cfg in premake.eachconfig(this) do %>
+ifeq ($(CONFIG),<%= _MAKE.esc(cfg.name)%>)
+<% for target, source in pairs(cfgpairs[cfg]) do %>
+<%= _MAKE.esc(target) %>: <%= _MAKE.esc(source) %>
+ $(COPY_RULE)
+<% end %>
+endif
+<% end %>
+
+# Copied file rules
+<% for target, source in pairs(copypairs) do %>
+<%= _MAKE.esc(target) %>: <%= _MAKE.esc(source) %>
+ $(COPY_RULE)
<% end %>
-REFERENCES += <%= table.implode(_MAKE.esc(premake.getlinks(this, "system", "basename")), '/r:', '', ' ') %>
+
+# Embedded file rules
+<% for _, fname in ipairs(embedded) do if path.getextension(fname) == ".resx" then %>
+<%= _MAKE.esc(getresourcefilename(this, fname)) %>: <%= _MAKE.esc(fname) %>
+ @$(RESGEN) $^ $@
+<% end end %>
diff --git a/src/base/functions.lua b/src/base/api.lua
index 0882b7e..f678d97 100644
--- a/src/base/functions.lua
+++ b/src/base/api.lua
@@ -1,6 +1,6 @@
--
--- functions.lua
--- Implementations of the solution, project, and configuration APIs.
+-- api.lua
+-- Implementation of the solution, project, and configuration APIs.
-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
--
@@ -267,15 +267,185 @@
end
},
}
+
+
+--
+-- End of metadata
+--
+
+
+
+--
+-- Check to see if a value exists in a list of values, using a
+-- case-insensitive match. If the value does exist, the canonical
+-- version contained in the list is returned, so future tests can
+-- use case-sensitive comparisions.
+--
+
+ local function checkvalue(value, allowed)
+ if (allowed) then
+ if (type(allowed) == "function") then
+ return allowed(value)
+ else
+ for _,v in ipairs(allowed) do
+ if (value:lower() == v:lower()) then
+ return v
+ end
+ end
+ return nil, "invalid value '" .. value .. "'"
+ end
+ else
+ return value
+ end
+ end
+
+
+
+--
+-- Retrieve the current object of a particular type from the session. The
+-- type may be "solution", "container" (the last activated solution or
+-- project), or "config" (the last activated configuration). Returns the
+-- requested container, or nil and an error message.
+--
+
+ function premake.getobject(t)
+ local container
+ if (t == "container" or t == "solution") then
+ container = premake.CurrentContainer
+ else
+ container = premake.CurrentConfiguration
+ end
+
+ if (t == "solution" and type(container) ~= "solution") then
+ container = nil
+ end
+
+ local msg
+ if (not container) then
+ if (t == "container") then
+ msg = "no active solution or project"
+ elseif (t == "solution") then
+ msg = "no active solution"
+ else
+ msg = "no active solution, project, or configuration"
+ end
+ end
+
+ return container, msg
+ end
+
+
+
+--
+-- Adds values to an array field of a solution/project/configuration. `ctype`
+-- specifies the container type (see premake.getobject) for the field.
+--
+ function premake.setarray(ctype, fieldname, value, allowed)
+ local container, err = premake.getobject(ctype)
+ if (not container) then
+ error(err, 3)
+ end
+
+ if (not container[fieldname]) then
+ container[fieldname] = { }
+ end
+
+ local function doinsert(value, depth)
+ if (type(value) == "table") then
+ for _,v in ipairs(value) do
+ doinsert(v, depth + 1)
+ end
+ else
+ value, err = checkvalue(value, allowed)
+ if (not value) then
+ error(err, depth)
+ end
+ table.insert(container[fieldname], value)
+ end
+ end
+
+ if (value) then
+ doinsert(value, 5)
+ end
+
+ return container[fieldname]
+ end
+
+
+
+--
+-- Adds values to an array-of-directories field of a solution/project/configuration.
+-- `ctype` specifies the container type (see premake.getobject) for the field. All
+-- values are converted to absolute paths before being stored.
+--
+
+ local function domatchedarray(ctype, fieldname, value, matchfunc)
+ local result = { }
+
+ function makeabsolute(value)
+ if (type(value) == "table") then
+ for _,item in ipairs(value) do
+ makeabsolute(item)
+ end
+ else
+ if value:find("*") then
+ makeabsolute(matchfunc(value))
+ else
+ table.insert(result, path.getabsolute(value))
+ end
+ end
+ end
+
+ makeabsolute(value)
+ return premake.setarray(ctype, fieldname, result)
+ end
+
+ function premake.setdirarray(ctype, fieldname, value)
+ return domatchedarray(ctype, fieldname, value, os.matchdirs)
+ end
+
+ function premake.setfilearray(ctype, fieldname, value)
+ return domatchedarray(ctype, fieldname, value, os.matchfiles)
+ end
+
+
+
+--
+-- Set a new value for a string field of a solution/project/configuration. `ctype`
+-- specifies the container type (see premake.getobject) for the field.
+--
+
+ function premake.setstring(ctype, fieldname, value, allowed)
+ -- find the container for this value
+ local container, err = premake.getobject(ctype)
+ if (not container) then
+ error(err, 4)
+ end
+
+ -- if a value was provided, set it
+ if (value) then
+ value, err = checkvalue(value, allowed)
+ if (not value) then
+ error(err, 4)
+ end
+
+ container[fieldname] = value
+ end
+
+ return container[fieldname]
+ end
+
+
+
--
--- The is the actual implementation of a getter/setter.
+-- The getter/setter implemention.
--
local function accessor(name, value)
- local kind = premake.fields[name].kind
- local scope = premake.fields[name].scope
+ local kind = premake.fields[name].kind
+ local scope = premake.fields[name].scope
local allowed = premake.fields[name].allowed
if (kind == "string") then
@@ -306,7 +476,7 @@
--
--- Project API functions
+-- Project object constructors.
--
function configuration(keywords)
@@ -362,7 +532,6 @@
-- attach a type
setmetatable(prj, {
__type = "project",
- __cfgcache = { }
})
prj.solution = sln
diff --git a/src/base/config.lua b/src/base/config.lua
deleted file mode 100644
index 3cc4464..0000000
--- a/src/base/config.lua
+++ /dev/null
@@ -1,415 +0,0 @@
---
--- config.lua
--- Support functions for working with configuration and configuration data.
--- Copyright (c) 2002-2008 Jason Perkins and the Premake project
---
-
-
---
--- These fields should *not* be copied into configurations.
---
-
- local nocopy =
- {
- blocks = true,
- keywords = true,
- projects = true,
- }
-
-
---
--- Returns an iterator for a project's configurations.
---
-
- function premake.eachconfig(prj)
- local i = 0
- local t = prj.solution.configurations
- return function ()
- i = i + 1
- if (i <= #t) then
- prj.filter.config = t[i]
- return premake.getconfig(prj, t[i])
- else
- prj.filter.config = nil
- end
- end
- end
-
-
-
---
--- Build a configuration object holding all of the settings that
--- match the specified filters.
---
-
- -- local function merges all fields from a block into the configuration
- local function copyfields(cfg, this)
- for field,value in pairs(this) do
- if (not nocopy[field]) then
- if (type(value) == "table") then
- if (not cfg[field]) then cfg[field] = { } end
- cfg[field] = table.join(cfg[field], value)
- else
- cfg[field] = value
- end
- end
- end
- end
-
- function premake.getconfig(prj, cfgname)
- -- make sure I've got the actual project object and not the root configuration
- if (prj.project) then prj = prj.project end
-
- -- see if this configuration has already been built and cached
- local meta = getmetatable(prj)
- local cachekey = cfgname or ""
- local cfg = meta.__cfgcache[cachekey]
- if (cfg) then
- return cfg
- end
-
- -- prepare the list of active terms, which will be used to filter the blocks
- local terms = premake.getactiveterms()
- terms.config = cfgname
-
- -- fields are copied first from the solution, then the solution's configs,
- -- then from the project, then the project's configs. Each can overwrite
- -- or add to the values set previously. The objdir field gets special
- -- treatment, in order to provide a project-level default and still enable
- -- solution-level overrides
-
- local cfg = { }
-
- copyfields(cfg, prj.solution)
- for _,blk in ipairs(prj.solution.blocks) do
- if (premake.iskeywordsmatch(blk.keywords, terms)) then
- copyfields(cfg, blk)
- end
- end
-
- copyfields(cfg, prj)
- if (not cfg.objdir) then cfg.objdir = path.join(prj.basedir, "obj") end
- for _,blk in ipairs(prj.blocks) do
- if (premake.iskeywordsmatch(blk.keywords, terms)) then
- copyfields(cfg, blk)
- end
- end
-
- -- remove excluded files
- local files = { }
- for _, fname in ipairs(cfg.files) do
- local excluded = false
- for _, exclude in ipairs(cfg.excludes) do
- excluded = (fname == exclude)
- if (excluded) then break end
- end
-
- if (not excluded) then
- table.insert(files, fname)
- end
- end
- cfg.files = files
-
- for name, field in pairs(premake.fields) do
-
- -- fix up paths, making them relative to project where needed
- if (field.kind == "path" or field.kind == "dirlist" or field.kind == "filelist") and (name ~= "location" and name ~= "basedir") then
- if (type(cfg[name]) == "table") then
- for i,p in ipairs(cfg[name]) do
- cfg[name][i] = path.getrelative(prj.location, p)
- end
- else
- if (cfg[name]) then
- cfg[name] = path.getrelative(prj.location, cfg[name])
- end
- end
- end
-
- -- re-key flag fields
- if (field.isflags) then
- local values = cfg[name]
- for _, flag in ipairs(values) do
- values[flag] = true
- end
- end
-
- end
-
- -- finish initialization
- meta.__cfgcache[cachekey] = cfg
- cfg.name = cfgname
- cfg.project = prj
-
- -- store the applicable tool for this configuration
- if cfg.language == "C" or cfg.language == "C++" then
- if _OPTIONS.cc then cfg.tool = premake[_OPTIONS.cc] end
- elseif cfg.language == "C#" then
- if _OPTIONS.dotnet then cfg.tool = premake[_OPTIONS.dotnet] end
- end
-
- -- precompute the target names and paths
- local action = premake.actions[_ACTION]
- local targetstyle = action.targetstyle or "linux"
- if (cfg.tool) then
- targetstyle = cfg.tool.targetstyle or targetstyle
- end
-
- cfg.buildtarget = premake.gettarget(cfg, "build", targetstyle)
- cfg.linktarget = premake.gettarget(cfg, "link", targetstyle)
- cfg.objectsdir = premake.getobjdir(cfg)
-
- local pathstyle = action.pathstyle or targetstyle
- if (pathstyle == "windows") then
- cfg.buildtarget.directory = path.translate(cfg.buildtarget.directory, "\\")
- cfg.buildtarget.fullpath = path.translate(cfg.buildtarget.fullpath, "\\")
- cfg.linktarget.directory = path.translate(cfg.linktarget.directory, "\\")
- cfg.linktarget.fullpath = path.translate(cfg.linktarget.fullpath, "\\")
- cfg.objectsdir = path.translate(cfg.objectsdir, "\\")
- end
-
- return cfg
- end
-
- function premake.getfileconfig(prj, filename, cfgname)
- -- make sure I've got the actual project object and not the root configuration
- if (prj.project) then prj = prj.project end
-
- -- prepare the list of active terms, which will be used to filter the blocks
- local terms = premake.getactiveterms()
- terms.filename = filename
- terms.config = cfgname
-
- -- fields are copied first from the solution blocks, then the project blocks
- local cfg = { }
- for _,blk in ipairs(prj.solution.blocks) do
- if (premake.iskeywordsmatch(blk.keywords, terms)) then
- copyfields(cfg, blk)
- end
- end
- for _,blk in ipairs(prj.blocks) do
- if (premake.iskeywordsmatch(blk.keywords, terms)) then
- copyfields(cfg, blk)
- end
- end
-
- cfg.name = cfgname
- cfg.filename = filename
- cfg.project = prj
- return cfg
- end
-
-
-
---
--- Returns a list of sibling projects on which the specified
--- configuration depends.
---
-
- function premake.getdependencies(cfg)
- local results = { }
- for _, link in ipairs(cfg.links) do
- -- is this a sibling project?
- local prj = premake.findproject(link)
- if (prj) then
- table.insert(results, prj)
- end
- end
- return results
- end
-
-
-
---
--- Returns a list of link targets. Kind may be one of "siblings" (only
--- return sibling projects), "system" (only return system libraries, or
--- non-siblings), or "all". Part is one of "name" (the decorated library
--- name with no path), "basename" (the undecorated name), "directory"
--- (just the directory containing the library), and "fullpath" (the
--- full path and decorated name).
---
-
- local function canlink(source, target)
- if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then return false end
- if (source.language == "C" or source.language == "C++") then
- if (target.language ~= "C" and target.language ~= "C++") then return false end
- return true
- elseif (source.language == "C#") then
- if (target.language ~= "C#") then return false end
- return true
- end
- end
-
-
- function premake.getlinks(cfg, kind, part)
- -- if I'm building a list of link directories, include libdirs
- local result = iif (part == "directory" and kind == "all", cfg.libdirs, {})
-
- for _, link in ipairs(cfg.links) do
- local item
-
- -- is this a sibling project?
- local prj = premake.findproject(link)
- if prj and (kind == "siblings" or kind == "all") then
-
- local prjcfg = premake.getconfig(prj, cfg.name)
- if canlink(cfg, prjcfg) then
- if (part == "directory") then
- item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location)
- elseif (part == "basename") then
- item = prjcfg.linktarget.basename
- else
- item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location)
- end
- end
-
- elseif not prj and (kind == "system" or kind == "all") then
-
- if (part == "directory") then
- local dir = path.getdirectory(link)
- if (dir ~= ".") then
- item = dir
- end
- elseif (part == "fullpath") then
- item = iif(premake.actions[_ACTION].targetstyle == "windows", link .. ".lib", link)
- else
- item = link
- end
-
- end
-
- if item then
- if premake.actions[_ACTION].targetstyle == "windows" then
- item = path.translate(item, "\\")
- end
- if not table.contains(result, item) then
- table.insert(result, item)
- end
- end
- end
-
- return result
- end
-
-
---
--- Return an object directory for the specified configuration which
--- is unique across the entire session.
---
-
- function premake.getobjdir(cfg)
- if (premake.isuniquevalue("objdir", cfg.objdir)) then
- return cfg.objdir
- end
-
- local fn = function (cfg) return path.join(cfg.objdir, cfg.name) end
- local objdir = fn(cfg)
- if (premake.isuniquevalue("objdir", objdir, fn)) then
- return objdir
- end
-
- return path.join(cfg.objdir, cfg.project.name .. "/" .. cfg.name)
- end
-
-
-
---
--- Assembles a target file name for a configuration. Direction is one of
--- "build" (the build target name) or "link" (the name to use when trying
--- to link against this target). Style is one of "windows" or "linux".
---
-
- function premake.gettarget(cfg, direction, style, os)
- -- normalize the arguments
- if not os then os = _OPTIONS.os or _OS end
- if (os == "bsd") then os = "linux" end
-
- local kind = cfg.kind
- if (cfg.language == "C" or cfg.language == "C++") then
- -- On Windows, shared libraries link against a static import library
- if (style == "windows" or os == "windows") and kind == "SharedLib" and direction == "link" then
- kind = "StaticLib"
- end
-
- -- Linux name conventions only apply to static libs on windows (by user request)
- if (style == "linux" and os == "windows" and kind ~= "StaticLib") then
- style = "windows"
- end
- elseif (cfg.language == "C#") then
- -- .NET always uses Windows naming conventions
- style = "windows"
- end
-
- -- Initialize the target components
- local field = iif(direction == "build", "target", "implib")
- local name = cfg[field.."name"] or cfg.targetname or cfg.project.name
- local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir)
- local prefix = ""
- local suffix = ""
-
- if style == "windows" then
- if kind == "ConsoleApp" or kind == "WindowedApp" then
- suffix = ".exe"
- elseif kind == "SharedLib" then
- suffix = ".dll"
- elseif kind == "StaticLib" then
- suffix = ".lib"
- end
- elseif style == "linux" then
- if (kind == "WindowedApp" and os == "macosx") then
- dir = path.join(dir, name .. ".app/Contents/MacOS")
- elseif kind == "SharedLib" then
- prefix = "lib"
- suffix = ".so"
- elseif kind == "StaticLib" then
- prefix = "lib"
- suffix = ".a"
- end
- end
-
- prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix
- suffix = cfg[field.."extension"] or cfg.targetextension or suffix
-
- local result = { }
- result.basename = name
- result.name = prefix .. name .. suffix
- result.directory = dir
- result.fullpath = path.join(result.directory, result.name)
- return result
- end
-
-
-
---
--- Returns true if all of the keywords are included the set of terms. Keywords
--- may use Lua's pattern matching syntax. Comparisons are case-insensitive.
---
-
- function premake.iskeywordsmatch(keywords, terms)
- local function test(kw)
- for _,term in pairs(terms) do
- if (term:match(kw)) then return true end
- end
- end
-
- for _,kw in ipairs(keywords) do
- -- make keyword pattern case insensitive
- kw = kw:gsub("(%%*)(%a)",
- function (p,a)
- if (p:len() % 2 == 1) then
- return p..a
- else
- return p.."["..a:upper()..a:lower().."]"
- end
- end)
-
- -- match it to a term
- if (not test(kw)) then
- return false
- end
- end
-
- return true
- end
-
-
-
diff --git a/src/base/configs.lua b/src/base/configs.lua
new file mode 100644
index 0000000..77d8bf8
--- /dev/null
+++ b/src/base/configs.lua
@@ -0,0 +1,305 @@
+--
+-- configs.lua
+--
+-- Once the project scripts have been run, flatten all of the configuration
+-- data down into simpler objects, keeping only the settings that apply to
+-- the current runtime environment.
+--
+-- Copyright (c) 2008 Jason Perkins and the Premake project
+--
+
+
+ -- do not copy these fields into the configurations
+ local nocopy =
+ {
+ blocks = true,
+ keywords = true,
+ projects = true,
+ }
+
+ -- leave these paths as absolute, rather than converting to project relative
+ local nofixup =
+ {
+ basedir = true,
+ location = true,
+ }
+
+
+
+--
+-- Returns a list of all of the active terms from the current environment.
+--
+
+ function premake.getactiveterms()
+ local terms = { _ACTION, os.get() }
+
+ -- add option keys or values
+ for key, value in pairs(_OPTIONS) do
+ if value then
+ table.insert(terms, value)
+ else
+ table.insert(terms, key)
+ end
+ end
+
+ return terms
+ end
+
+
+
+--
+-- Returns true if all of the keywords are included the set of terms. Keywords
+-- may use Lua's pattern matching syntax. Comparisons are case-insensitive.
+--
+
+ function premake.iskeywordsmatch(keywords, terms)
+ local hasrequired = false
+
+ local function test(kw)
+ for termkey, term in pairs(terms) do
+ if (term:match(kw)) then
+ if termkey == "required" then hasrequired = true end
+ return true
+ end
+ end
+ end
+
+ for _, kw in ipairs(keywords) do
+ -- make keyword pattern case insensitive
+ kw = kw:gsub("(%%*)(%a)",
+ function (p,a)
+ if (p:len() % 2 == 1) then
+ return p..a
+ else
+ return p.."["..a:upper()..a:lower().."]"
+ end
+ end)
+
+ -- match it to a term
+ if (not test(kw)) then
+ return false
+ end
+ end
+
+ if terms.required and not hasrequired then
+ return false
+ else
+ return true
+ end
+ end
+
+
+
+--
+-- Copies all of the fields from an object into a configuration object. List
+-- fields are appended, string fields are overwritten.
+--
+
+ local function copyfields(cfg, this)
+ for field,value in pairs(this) do
+ if (not nocopy[field]) then
+ if (type(value) == "table") then
+ if (not cfg[field]) then cfg[field] = { } end
+ cfg[field] = table.join(cfg[field], value)
+ else
+ cfg[field] = value
+ end
+ end
+ end
+ end
+
+
+
+--
+-- Build a configuration object, given a project and a set of configuration terms.
+-- Used to build the base objects for both project and file configurations.
+--
+
+ local function buildconfig(prj, terms)
+ -- fields are copied first from the solution, then the solution's configs,
+ -- then from the project, then the project's configs. Each can overwrite
+ -- or add to the values set previously. The objdir field gets special
+ -- treatment, in order to provide a project-level default and still enable
+ -- solution-level overrides
+
+ local cfg = { }
+
+ copyfields(cfg, prj.solution)
+ for _,blk in ipairs(prj.solution.blocks) do
+ if (premake.iskeywordsmatch(blk.keywords, terms)) then
+ copyfields(cfg, blk)
+ end
+ end
+
+ copyfields(cfg, prj)
+ for _,blk in ipairs(prj.blocks) do
+ if (premake.iskeywordsmatch(blk.keywords, terms)) then
+ copyfields(cfg, blk)
+ end
+ end
+
+ return cfg
+ end
+
+
+
+--
+-- Builds a configuration object for a particular project/configuration pair. Flattens
+-- the object hierarchy, and discards any settings that do not apply to this environment.
+--
+
+ local function buildprojectconfig(prj, cfgname)
+ -- create the base configuration, flattening the list of objects and
+ -- filtering out settings which do not match the current environment
+ local terms = premake.getactiveterms()
+ terms.config = cfgname
+
+ local cfg = buildconfig(prj, terms)
+ cfg.name = cfgname
+ cfg.project = prj
+
+ -- remove excluded files from the file list
+ local files = { }
+ for _, fname in ipairs(cfg.files) do
+ local excluded = false
+ for _, exclude in ipairs(cfg.excludes) do
+ excluded = (fname == exclude)
+ if (excluded) then break end
+ end
+
+ if (not excluded) then
+ table.insert(files, fname)
+ end
+ end
+ cfg.files = files
+
+ -- fixup the data
+ for name, field in pairs(premake.fields) do
+ -- convert absolute paths to project relative
+ if (field.kind == "path" or field.kind == "dirlist" or field.kind == "filelist") and (not nofixup[name]) then
+ if type(cfg[name]) == "table" then
+ for i,p in ipairs(cfg[name]) do cfg[name][i] = path.getrelative(prj.location, p) end
+ else
+ if cfg[name] then cfg[name] = path.getrelative(prj.location, cfg[name]) end
+ end
+ end
+
+ -- re-key flag fields for faster lookups
+ if field.isflags then
+ local values = cfg[name]
+ for _, flag in ipairs(values) do values[flag] = true end
+ end
+ end
+
+ -- build configuration objects for all files
+ cfg.__fileconfigs = { }
+ for _, fname in ipairs(cfg.files) do
+ terms.required = fname
+ local fcfg = buildconfig(prj, terms)
+ fcfg.name = fname
+ -- add indexed by name and integer
+ cfg.__fileconfigs[fname] = fcfg
+ table.insert(cfg.__fileconfigs, fcfg)
+ end
+
+ return cfg
+ end
+
+
+
+--
+-- Pre-computes the build target, link target, and a unique objects directory
+-- for a configuration.
+--
+
+ local function buildtargets(cfg)
+
+ -- deduce and store the applicable tool for this configuration
+ if cfg.language == "C" or cfg.language == "C++" then
+ if _OPTIONS.cc then cfg.tool = premake[_OPTIONS.cc] end
+ elseif cfg.language == "C#" then
+ if _OPTIONS.dotnet then cfg.tool = premake[_OPTIONS.dotnet] end
+ end
+
+ -- deduce the target and path style from the current action/tool pairing
+ local action = premake.actions[_ACTION]
+ local targetstyle = action.targetstyle or "linux"
+ if (cfg.tool) then
+ targetstyle = cfg.tool.targetstyle or targetstyle
+ end
+
+ -- precompute the target names and paths
+ cfg.buildtarget = premake.gettarget(cfg, "build", targetstyle)
+ cfg.linktarget = premake.gettarget(cfg, "link", targetstyle)
+
+ -- build a unique objects directory
+ local function getbasedir(cfg)
+ return path.join(cfg.location, cfg.objdir or cfg.project.objdir or "obj")
+ end
+
+ local function getuniquedir(cfg)
+ local thisbase = getbasedir(cfg)
+ local thislocal = path.join(thisbase, cfg.name)
+ local isbasematched = false
+ for _, sln in ipairs(_SOLUTIONS) do
+ for _, prj in ipairs(sln.projects) do
+ for _, thatcfg in pairs(prj.__configs) do
+ if thatcfg ~= cfg then
+ local thatbase = getbasedir(thatcfg)
+ if thisbase == thatbase then
+ isbasematched = true
+ if thislocal == path.join(thatbase, thatcfg.name) then
+ return path.join(thislocal, cfg.project.name)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return iif(isbasematched, thislocal, thisbase)
+ end
+
+ cfg.objectsdir = path.getrelative(cfg.location, getuniquedir(cfg))
+
+ -- translate the paths as appropriate
+ local pathstyle = action.pathstyle or targetstyle
+ if (pathstyle == "windows") then
+ cfg.buildtarget.directory = path.translate(cfg.buildtarget.directory, "\\")
+ cfg.buildtarget.fullpath = path.translate(cfg.buildtarget.fullpath, "\\")
+ cfg.linktarget.directory = path.translate(cfg.linktarget.directory, "\\")
+ cfg.linktarget.fullpath = path.translate(cfg.linktarget.fullpath, "\\")
+ cfg.objectsdir = path.translate(cfg.objectsdir, "\\")
+ end
+ end
+
+
+
+--
+-- Takes the configuration information stored in solution->project->block
+-- hierarchy and flattens it all down into one object per configuration.
+-- These objects are cached with the project, and can be retrieved by
+-- calling the eachconfig() iterator function.
+--
+
+ function premake.buildconfigs()
+ -- walk the object tree once and flatten the configurations
+ for _, sln in ipairs(_SOLUTIONS) do
+ for _, prj in ipairs(sln.projects) do
+ prj.__configs = { }
+ prj.__configs[""] = buildprojectconfig(prj)
+ for _, name in ipairs(sln.configurations) do
+ prj.__configs[name] = buildprojectconfig(prj, name)
+ end
+ end
+ end
+
+ -- walk it again and build the targets and unique directories
+ for _, sln in ipairs(_SOLUTIONS) do
+ for _, prj in ipairs(sln.projects) do
+ for _, cfg in pairs(prj.__configs) do
+ buildtargets(cfg)
+ end
+ end
+ end
+ end
diff --git a/src/base/os.lua b/src/base/os.lua
index f150af9..42ca8df 100644
--- a/src/base/os.lua
+++ b/src/base/os.lua
@@ -6,12 +6,21 @@
--
+-- Retrieve the current operating system ID string.
+--
+
+ function os.get()
+ return _OPTIONS.os or _OS
+ end
+
+
+
+--
-- Check the current operating system; may be set with the /os command line flag.
--
function os.is(id)
- local current = _OPTIONS["os"] or _OS
- return (current:lower() == id:lower())
+ return (os.get():lower() == id:lower())
end
diff --git a/src/base/premake.lua b/src/base/premake.lua
deleted file mode 100644
index 31ebbcf..0000000
--- a/src/base/premake.lua
+++ /dev/null
@@ -1,196 +0,0 @@
---
--- premake.lua
--- Main (top level) application logic for Premake.
--- Copyright (c) 2002-2008 Jason Perkins and the Premake project
---
-
-
---
--- Check the specified tools (/cc, /dotnet, etc.) against the current action
--- to make sure they are compatible and supported.
---
-
- function premake.checktools()
- local action = premake.actions[_ACTION]
- if (not action.valid_tools) then
- return true
- end
-
- for tool, values in pairs(action.valid_tools) do
- if (_OPTIONS[tool]) then
- if (not table.contains(values, _OPTIONS[tool])) then
- return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)"
- end
- else
- _OPTIONS[tool] = values[1]
- end
- end
-
- return true
- end
-
-
-
---
--- Validate the command-line options.
---
-
- function premake.checkoptions()
- for key, value in pairs(_OPTIONS) do
- -- is this a valid option?
- local opt = premake.options[key]
- if (not opt) then
- return false, "invalid option '" .. key .. "'"
- end
-
- -- does it need a value?
- if (opt.value and value == "") then
- return false, "no value specified for option '" .. key .. "'"
- end
-
- -- is the value allowed?
- if (opt.allowed) then
- for _, match in ipairs(opt.allowed) do
- if (match[1] == value) then return true end
- end
- return false, "invalid value '" .. value .. "' for option '" .. key .. "'"
- end
- end
- return true
- end
-
-
---
--- Check to see if a value exists in a list of values, using a
--- case-insensitive match. If the value does exist, the canonical
--- version contained in the list is returned, so future tests can
--- use case-sensitive comparisions.
---
-
- function premake.checkvalue(value, allowed)
- if (allowed) then
- if (type(allowed) == "function") then
- return allowed(value)
- else
- for _,v in ipairs(allowed) do
- if (value:lower() == v:lower()) then
- return v
- end
- end
- return nil, "invalid value '" .. value .. "'"
- end
- else
- return value
- end
- end
-
-
-
---
--- Fire a particular action. Generates the output files from the templates
--- listed in the action descriptor, and calls any registered handler functions.
---
-
- function premake.doaction(name)
- local action = premake.actions[name]
-
- -- walk the session objects and generate files from the templates
- local function generatefiles(this, templates)
- if (not templates) then return end
- for _,tmpl in ipairs(templates) do
- local output = true
- if (tmpl[3]) then
- output = tmpl[3](this)
- end
- if (output) then
- local fname = premake.getoutputname(this, tmpl[1])
- local f, err = io.open(fname, "wb")
- if (not f) then
- error(err, 0)
- end
- io.output(f)
-
- -- call the template function to generate the output
- tmpl[2](this)
-
- io.output():close()
- end
- end
- end
-
- for _,sln in ipairs(_SOLUTIONS) do
- generatefiles(sln, action.solutiontemplates)
- for prj in premake.eachproject(sln) do
- generatefiles(prj, action.projecttemplates)
- end
- end
-
- if (action.execute) then
- action.execute()
- end
- end
-
-
-
---
--- Apply XML escaping to a value.
---
-
- function premake.esc(value)
- if (type(value) == "table") then
- local result = { }
- for _,v in ipairs(value) do
- table.insert(result, premake.esc(v))
- end
- return result
- else
- value = value:gsub('&', "&amp;")
- value = value:gsub('"', "&quot;")
- value = value:gsub("'", "&apos;")
- value = value:gsub('<', "&lt;")
- value = value:gsub('>', "&gt;")
- value = value:gsub('\r', "&#x0D;")
- value = value:gsub('\n', "&#x0A;")
- return value
- end
- end
-
-
-
---
--- Returns a list of all of the active terms from the current environment.
---
-
- local _terms
- function premake.getactiveterms()
- if (not _terms) then
- _terms = { }
- table.insert(_terms, _ACTION)
- table.insert(_terms, _OS)
- for k,_ in pairs(_OPTIONS) do
- table.insert(_terms, k)
- end
- end
- return _terms
- end
-
-
-
---
--- Converts a project object and a template filespec (the first value in an
--- action's template reference) into a filename for that template's output.
--- The filespec may be either a file extension, or a function.
---
-
- function premake.getoutputname(this, namespec)
- local fname
- if (type(namespec) == "function") then
- fname = namespec(this)
- else
- fname = this.name .. namespec
- end
- return path.join(this.location, fname)
- end
-
-
-
diff --git a/src/base/project.lua b/src/base/project.lua
index 47751e1..b5c6829 100644
--- a/src/base/project.lua
+++ b/src/base/project.lua
@@ -1,117 +1,231 @@
--
-- project.lua
--- Support functions for working with projects and project data.
+-- Functions for working with the project data.
-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
--
+
--
--- Performs a sanity check all all of the solutions and projects
--- in the session to be sure they meet some minimum requirements.
+-- Apply XML escaping to a value.
--
- function premake.checkprojects()
- local action = premake.actions[_ACTION]
-
- for _,sln in ipairs(_SOLUTIONS) do
- -- every solution must have at least one project
- if (#sln.projects == 0) then
- return nil, "solution '" .. sln.name .. "' needs at least one project"
+ function premake.esc(value)
+ if (type(value) == "table") then
+ local result = { }
+ for _,v in ipairs(value) do
+ table.insert(result, premake.esc(v))
end
-
- -- every solution must list configurations
- if (not sln.configurations or #sln.configurations == 0) then
- return nil, "solution '" .. sln.name .. "' needs configurations"
+ return result
+ else
+ value = value:gsub('&', "&amp;")
+ value = value:gsub('"', "&quot;")
+ value = value:gsub("'", "&apos;")
+ value = value:gsub('<', "&lt;")
+ value = value:gsub('>', "&gt;")
+ value = value:gsub('\r', "&#x0D;")
+ value = value:gsub('\n', "&#x0A;")
+ return value
+ end
+ end
+
+
+
+--
+-- Returns a list of sibling projects on which the specified
+-- configuration depends. This is used to specify project
+-- dependencies, usually within a solution.
+--
+
+ function premake.getdependencies(cfg)
+ local results = { }
+ for _, link in ipairs(cfg.links) do
+ local prj = premake.findproject(link)
+ if (prj) then
+ table.insert(results, prj)
end
-
- for _,prj in ipairs(sln.projects) do
- local cfg = premake.getconfig(prj)
+ end
+ return results
+ end
- -- every project must have a language
- if (not cfg.language) then
- return nil, "project '" ..prj.name .. "' needs a language"
- end
+
+
+--
+-- Returns a list of link targets. Kind may be one of:
+-- siblings - linkable sibling projects
+-- system - system (non-subling) libraries
+-- dependencies - all sibling dependencies, including non-linkable
+-- all - return everything
+--
+-- Part may be one of:
+-- name - the decorated library name with no directory
+-- basename - the undecorated library name
+-- directory - just the directory, no name
+-- fullpath - full path with decorated name
+--
+
+ function premake.getlinks(cfg, kind, part)
+ -- if I'm building a list of link directories, include libdirs
+ local result = iif (part == "directory" and kind == "all", cfg.libdirs, {})
+
+ local function canlink(source, target)
+ if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then return false end
+ if (source.language == "C" or source.language == "C++") then
+ if (target.language ~= "C" and target.language ~= "C++") then return false end
+ return true
+ elseif (source.language == "C#") then
+ if (target.language ~= "C#") then return false end
+ return true
+ end
+ end
+
+ for _, link in ipairs(cfg.links) do
+ local item
+
+ -- is this a sibling project?
+ local prj = premake.findproject(link)
+ if prj and kind ~= "system" then
- -- and the action must support it
- if (action.valid_languages) then
- if (not table.contains(action.valid_languages, cfg.language)) then
- return nil, "the " .. action.shortname .. " action does not support " .. cfg.language .. " projects"
+ local prjcfg = premake.getconfig(prj, cfg.name)
+ if kind == "dependencies" or canlink(cfg, prjcfg) then
+ if (part == "directory") then
+ item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location)
+ elseif (part == "basename") then
+ item = prjcfg.linktarget.basename
+ else
+ item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location)
end
end
-
- for _,cfgname in ipairs(sln.configurations) do
- cfg = premake.getconfig(prj, cfgname)
-
- -- every config must have a kind
- if (not cfg.kind) then
- return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfgname .. "'"
- end
+
+ elseif not prj and (kind == "system" or kind == "all") then
- -- and the action must support it
- if (action.valid_kinds) then
- if (not table.contains(action.valid_kinds, cfg.kind)) then
- return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects"
- end
+ if (part == "directory") then
+ local dir = path.getdirectory(link)
+ if (dir ~= ".") then
+ item = dir
end
+ elseif (part == "fullpath") then
+ item = iif(premake.actions[_ACTION].targetstyle == "windows", link .. ".lib", link)
+ else
+ item = link
end
end
+
+ if item then
+ if premake.actions[_ACTION].targetstyle == "windows" then
+ item = path.translate(item, "\\")
+ end
+ if not table.contains(result, item) then
+ table.insert(result, item)
+ end
+ end
end
-
- return true
- end
+ return result
+ end
+
--
--- Returns an iterator for a solution's projects.
+-- Assembles a target file name for a configuration. Direction is one of
+-- "build" (the build target name) or "link" (the name to use when trying
+-- to link against this target). Style is one of "windows" or "linux".
--
- function premake.eachproject(sln)
- local i = 0
- return function ()
- i = i + 1
- if (i <= #sln.projects) then
- local prj = sln.projects[i]
+ function premake.gettarget(cfg, direction, style, os)
+ -- normalize the arguments
+ if not os then os = _G["os"].get() end
+ if (os == "bsd") then os = "linux" end
+
+ local kind = cfg.kind
+ if (cfg.language == "C" or cfg.language == "C++") then
+ -- On Windows, shared libraries link against a static import library
+ if (style == "windows" or os == "windows") and kind == "SharedLib" and direction == "link" then
+ kind = "StaticLib"
+ end
+
+ -- Linux name conventions only apply to static libs on windows (by user request)
+ if (style == "linux" and os == "windows" and kind ~= "StaticLib") then
+ style = "windows"
+ end
+ elseif (cfg.language == "C#") then
+ -- .NET always uses Windows naming conventions
+ style = "windows"
+ end
- -- merge solution and project values
- local merged = premake.getconfig(prj)
- setmetatable(merged, getmetatable(prj))
- merged.name = prj.name
- merged.blocks = prj.blocks
- return merged
+ -- Initialize the target components
+ local field = iif(direction == "build", "target", "implib")
+ local name = cfg[field.."name"] or cfg.targetname or cfg.project.name
+ local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir)
+ local prefix = ""
+ local suffix = ""
+
+ if style == "windows" then
+ if kind == "ConsoleApp" or kind == "WindowedApp" then
+ suffix = ".exe"
+ elseif kind == "SharedLib" then
+ suffix = ".dll"
+ elseif kind == "StaticLib" then
+ suffix = ".lib"
+ end
+ elseif style == "linux" then
+ if (kind == "WindowedApp" and os == "macosx") then
+ dir = path.join(dir, name .. ".app/Contents/MacOS")
+ elseif kind == "SharedLib" then
+ prefix = "lib"
+ suffix = ".so"
+ elseif kind == "StaticLib" then
+ prefix = "lib"
+ suffix = ".a"
end
end
+
+ prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix
+ suffix = cfg[field.."extension"] or cfg.targetextension or suffix
+
+ local result = { }
+ result.basename = name
+ result.name = prefix .. name .. suffix
+ result.directory = dir
+ result.fullpath = path.join(result.directory, result.name)
+ return result
end
-
-
---
--- Locate a project by name; case insensitive.
+
+
+--
+-- Iterator for a project's configuration objects.
--
- function premake.findproject(name)
- name = name:lower()
- for _, sln in ipairs(_SOLUTIONS) do
- for _, prj in ipairs(sln.projects) do
- if (prj.name:lower() == name) then
- return prj
- end
+ function premake.eachconfig(prj)
+ -- I probably have the project root config, rather than the actual project
+ if prj.project then prj = prj.project end
+ local i = 0
+ local t = prj.solution.configurations
+ return function ()
+ i = i + 1
+ if (i <= #t) then
+ return prj.__configs[t[i]]
end
end
end
-
+
--
--- Locate a file in a project with a given extension; used locate "special"
--- items such as Windows .def files.
+-- Iterator for a project's files; returns a file configuration object.
--
- function premake.findfile(prj, extension)
- for _, fname in ipairs(prj.files) do
- if (path.getextension(fname) == extension) then
- return fname
+ function premake.eachfile(prj)
+ -- project root config contains the file config list
+ if not prj.project then prj = premake.getconfig(prj) end
+ local i = 0
+ local t = prj.files
+ return function ()
+ i = i + 1
+ if (i <= #t) then
+ return prj.__fileconfigs[t[i]]
end
end
end
@@ -119,174 +233,72 @@
--
--- Retrieve the current object of the a particular type from the session.
--- The type may be "solution", "container" (the last activated solution or
--- project), or "config" (the last activated configuration). Returns the
--- requested container, or nil and an error message.
+-- Iterator for a solution's projects, or rather project root configurations.
+-- These configuration objects include all settings related to the project,
+-- regardless of where they were originally specified.
--
- function premake.getobject(t)
- local container
-
- if (t == "container" or t == "solution") then
- container = premake.CurrentContainer
- else
- container = premake.CurrentConfiguration
- end
-
- if (t == "solution" and type(container) ~= "solution") then
- container = nil
- end
-
- local msg
- if (not container) then
- if (t == "container") then
- msg = "no active solution or project"
- elseif (t == "solution") then
- msg = "no active solution"
- else
- msg = "no active solution, project, or configuration"
+ function premake.eachproject(sln)
+ local i = 0
+ return function ()
+ i = i + 1
+ if (i <= #sln.projects) then
+ local prj = sln.projects[i]
+ local cfg = premake.getconfig(prj)
+ cfg.name = prj.name
+ cfg.blocks = prj.blocks
+ return cfg
end
end
-
- return container, msg
end
-
---
--- Determines if a field value is unique across all configurations of
--- all projects in the session. Used to create unique output targets.
+
+--
+-- Locate a project by name; case insensitive.
--
- function premake.isuniquevalue(fieldname, value, fn)
- local count = 0
+ function premake.findproject(name)
+ name = name:lower()
for _, sln in ipairs(_SOLUTIONS) do
for _, prj in ipairs(sln.projects) do
- for _, cfgname in ipairs(sln.configurations) do
- local cfg = premake.getconfig(prj, cfgname)
-
- local tst
- if (fn) then
- tst = fn(cfg)
- else
- tst = cfg[fieldname]
- end
-
- if (tst == value) then
- count = count + 1
- if (count > 1) then return false end
- end
+ if (prj.name:lower() == name) then
+ return prj
end
end
end
- return true
end
-
+
--
--- Adds values to an array field of a solution/project/configuration. `ctype`
--- specifies the container type (see premake.getobject) for the field.
+-- Locate a file in a project with a given extension; used to locate "special"
+-- items such as Windows .def files.
--
- function premake.setarray(ctype, fieldname, value, allowed)
- local container, err = premake.getobject(ctype)
- if (not container) then
- error(err, 3)
- end
-
- if (not container[fieldname]) then
- container[fieldname] = { }
- end
-
- local function doinsert(value, depth)
- if (type(value) == "table") then
- for _,v in ipairs(value) do
- doinsert(v, depth + 1)
- end
- else
- value, err = premake.checkvalue(value, allowed)
- if (not value) then
- error(err, depth)
- end
- table.insert(container[fieldname], value)
+ function premake.findfile(prj, extension)
+ for _, fname in ipairs(prj.files) do
+ if (path.getextension(fname) == extension) then
+ return fname
end
end
-
- if (value) then
- doinsert(value, 5)
- end
-
- return container[fieldname]
end
-
---
--- Adds values to an array-of-directories field of a solution/project/configuration.
--- `ctype` specifies the container type (see premake.getobject) for the field. All
--- values are converted to absolute paths before being stored.
---
- local function domatchedarray(ctype, fieldname, value, matchfunc)
- local result = { }
-
- function makeabsolute(value)
- if (type(value) == "table") then
- for _,item in ipairs(value) do
- makeabsolute(item)
- end
- else
- if value:find("*") then
- makeabsolute(matchfunc(value))
- else
- table.insert(result, path.getabsolute(value))
- end
- end
- end
-
- makeabsolute(value)
- return premake.setarray(ctype, fieldname, result)
- end
-
- function premake.setdirarray(ctype, fieldname, value)
- return domatchedarray(ctype, fieldname, value, os.matchdirs)
- end
-
- function premake.setfilearray(ctype, fieldname, value)
- return domatchedarray(ctype, fieldname, value, os.matchfiles)
- end
-
-
-
--
--- Set a new value for a string field of a solution/project/configuration. `ctype`
--- specifies the container type (see premake.getobject) for the field.
+-- Retrieve a configuration for a given project/configuration pairing. If
+-- `cfgname` is nil, the project's root configuration will be returned.
--
- function premake.setstring(ctype, fieldname, value, allowed)
- -- find the container for this value
- local container, err = premake.getobject(ctype)
- if (not container) then
- error(err, 4)
- end
-
- -- if a value was provided, set it
- if (value) then
- value, err = premake.checkvalue(value, allowed)
- if (not value) then
- error(err, 4)
- end
-
- container[fieldname] = value
- end
-
- return container[fieldname]
+ function premake.getconfig(prj, cfgname)
+ -- might have the root configuration, rather than the actual project
+ if prj.project then prj = prj.project end
+ return prj.__configs[cfgname or ""]
end
-
-
-
+
+
+
--
-- Walk the list of source code files, breaking them into "groups" based
-- on the directory hierarchy.
diff --git a/src/base/table.lua b/src/base/table.lua
index 1462a31..35cd62d 100644
--- a/src/base/table.lua
+++ b/src/base/table.lua
@@ -74,8 +74,14 @@
function table.translate(arr, translation)
local result = { }
for _, value in ipairs(arr) do
- if (translation[value]) then
- table.insert(result, translation[value])
+ local tvalue
+ if type(translation) == "function" then
+ tvalue = translation(value)
+ else
+ tvalue = translation[value]
+ end
+ if (tvalue) then
+ table.insert(result, tvalue)
end
end
return result
diff --git a/src/base/template.lua b/src/base/template.lua
index 3e7300f..bfab77d 100644
--- a/src/base/template.lua
+++ b/src/base/template.lua
@@ -109,6 +109,24 @@
--
+-- Converts a project object and a template filespec (the first value in an
+-- action's template reference) into a filename for that template's output.
+-- The filespec may be either a file extension, or a function.
+--
+
+ function premake.getoutputname(this, namespec)
+ local fname
+ if (type(namespec) == "function") then
+ fname = namespec(this)
+ else
+ fname = this.name .. namespec
+ end
+ return path.join(this.location, fname)
+ end
+
+
+
+--
-- Load a template from a file and convert it to a template function.
--
diff --git a/src/base/validate.lua b/src/base/validate.lua
new file mode 100644
index 0000000..25c245b
--- /dev/null
+++ b/src/base/validate.lua
@@ -0,0 +1,115 @@
+--
+-- validate.lua
+-- Tests to validate the run-time environment before starting the action.
+-- Copyright (c) 2002-2008 Jason Perkins and the Premake project
+--
+
+
+--
+-- Validate the command-line options.
+--
+
+ function premake.checkoptions()
+ for key, value in pairs(_OPTIONS) do
+ -- is this a valid option?
+ local opt = premake.options[key]
+ if (not opt) then
+ return false, "invalid option '" .. key .. "'"
+ end
+
+ -- does it need a value?
+ if (opt.value and value == "") then
+ return false, "no value specified for option '" .. key .. "'"
+ end
+
+ -- is the value allowed?
+ if (opt.allowed) then
+ for _, match in ipairs(opt.allowed) do
+ if (match[1] == value) then return true end
+ end
+ return false, "invalid value '" .. value .. "' for option '" .. key .. "'"
+ end
+ end
+ return true
+ end
+
+
+
+--
+-- Performs a sanity check all all of the solutions and projects
+-- in the session to be sure they meet some minimum requirements.
+--
+
+ function premake.checkprojects()
+ local action = premake.actions[_ACTION]
+
+ for _, sln in ipairs(_SOLUTIONS) do
+
+ -- every solution must have at least one project
+ if (#sln.projects == 0) then
+ return nil, "solution '" .. sln.name .. "' needs at least one project"
+ end
+
+ -- every solution must provide a list of configurations
+ if (#sln.configurations == 0) then
+ return nil, "solution '" .. sln.name .. "' needs configurations"
+ end
+
+ for prj in premake.eachproject(sln) do
+
+ -- every project must have a language
+ if (not prj.language) then
+ return nil, "project '" ..prj.name .. "' needs a language"
+ end
+
+ -- and the action must support it
+ if (action.valid_languages) then
+ if (not table.contains(action.valid_languages, prj.language)) then
+ return nil, "the " .. action.shortname .. " action does not support " .. prj.language .. " projects"
+ end
+ end
+
+ for cfg in premake.eachconfig(prj) do
+
+ -- every config must have a kind
+ if (not cfg.kind) then
+ return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfgname .. "'"
+ end
+
+ -- and the action must support it
+ if (action.valid_kinds) then
+ if (not table.contains(action.valid_kinds, cfg.kind)) then
+ return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects"
+ end
+ end
+
+ end
+ end
+ end
+ return true
+ end
+
+
+--
+-- Check the specified tools (/cc, /dotnet, etc.) against the current action
+-- to make sure they are compatible and supported.
+--
+
+ function premake.checktools()
+ local action = premake.actions[_ACTION]
+ if (not action.valid_tools) then
+ return true
+ end
+
+ for tool, values in pairs(action.valid_tools) do
+ if (_OPTIONS[tool]) then
+ if (not table.contains(values, _OPTIONS[tool])) then
+ return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)"
+ end
+ else
+ _OPTIONS[tool] = values[1]
+ end
+ end
+
+ return true
+ end
diff --git a/src/tools/csc.lua b/src/tools/csc.lua
index 035246c..a9908d0 100644
--- a/src/tools/csc.lua
+++ b/src/tools/csc.lua
@@ -23,7 +23,23 @@
}
+--
+-- Return the default build action for a given file, based on the file extension.
+--
+ function premake.csc.getbuildaction(fname)
+ local ext = path.getextension(fname):lower()
+ if ext == ".cs" then
+ return "Compile"
+ elseif ext == ".resx" then
+ return "Embed"
+ elseif ext == ".asax" or ext == ".aspx" then
+ return "Copy"
+ end
+ end
+
+
+
--
-- Returns the compiler filename (they all use the same arguments)
--
@@ -32,13 +48,14 @@
if (_OPTIONS.dotnet == "ms") then
return "csc"
elseif (_OPTIONS.dotnet == "mono") then
- return "mcs"
+ return "gmcs"
else
return "cscc"
end
end
+
--
-- Returns a list of compiler flags, based on the supplied configuration.
--
@@ -47,3 +64,19 @@
local result = table.translate(cfg.flags, flags)
return result
end
+
+
+
+--
+-- Translates the Premake kind into the CSC kind string.
+--
+
+ function premake.csc.getkind(cfg)
+ if (cfg.kind == "ConsoleApp") then
+ return "exe"
+ elseif (cfg.kind == "WindowedApp") then
+ return "winexe"
+ elseif (cfg.kind == "SharedLib") then
+ return "library"
+ end
+ end \ No newline at end of file
diff --git a/tests/premake4.lua b/tests/premake4.lua
index 662de57..ab7d27f 100644
--- a/tests/premake4.lua
+++ b/tests/premake4.lua
@@ -12,8 +12,8 @@
dofile("test_table.lua")
dofile("test_template.lua")
dofile("test_premake.lua")
- dofile("test_config.lua")
dofile("test_project.lua")
+ dofile("test_api.lua")
dofile("test_targets.lua")
dofile("test_functions.lua")
diff --git a/tests/test_api.lua b/tests/test_api.lua
new file mode 100644
index 0000000..dfeda46
--- /dev/null
+++ b/tests/test_api.lua
@@ -0,0 +1,116 @@
+--
+-- tests/test_api.lua
+-- Automated test suite for the project API support functions.
+-- Copyright (c) 2008 Jason Perkins and the Premake project
+--
+
+ T.api = { }
+
+
+--
+-- premake.getobject() tests
+--
+
+ function T.api.getobject_RaisesError_OnNoContainer()
+ premake.CurrentContainer = nil
+ c, err = premake.getobject("container")
+ test.istrue(c == nil)
+ test.isequal("no active solution or project", err)
+ end
+
+ function T.api.getobject_RaisesError_OnNoActiveSolution()
+ premake.CurrentContainer = { }
+ c, err = premake.getobject("solution")
+ test.istrue(c == nil)
+ test.isequal("no active solution", err)
+ end
+
+ function T.api.getobject_RaisesError_OnNoActiveConfig()
+ premake.CurrentConfiguration = nil
+ c, err = premake.getobject("config")
+ test.istrue(c == nil)
+ test.isequal("no active solution, project, or configuration", err)
+ end
+
+
+--
+-- premake.setarray() tests
+--
+
+ function T.api.setarray_Inserts_OnStringValue()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { }
+ premake.setarray("config", "myfield", "hello")
+ test.isequal("hello", premake.CurrentConfiguration.myfield[1])
+ end
+
+ function T.api.setarray_Inserts_OnTableValue()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { }
+ premake.setarray("config", "myfield", { "hello", "goodbye" })
+ test.isequal("hello", premake.CurrentConfiguration.myfield[1])
+ test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
+ end
+
+ function T.api.setarray_Appends_OnNewValues()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { "hello" }
+ premake.setarray("config", "myfield", "goodbye")
+ test.isequal("hello", premake.CurrentConfiguration.myfield[1])
+ test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
+ end
+
+ function T.api.setarray_FlattensTables()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { }
+ premake.setarray("config", "myfield", { {"hello"}, {"goodbye"} })
+ test.isequal("hello", premake.CurrentConfiguration.myfield[1])
+ test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
+ end
+
+ function T.api.setarray_RaisesError_OnInvalidValue()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { }
+ ok, err = pcall(function () premake.setarray("config", "myfield", "bad", { "Good", "Better", "Best" }) end)
+ test.isfalse(ok)
+ end
+
+ function T.api.setarray_CorrectsCase_OnConstrainedValue()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = { }
+ premake.setarray("config", "myfield", "better", { "Good", "Better", "Best" })
+ test.isequal("Better", premake.CurrentConfiguration.myfield[1])
+ end
+
+
+
+--
+-- premake.setstring() tests
+--
+
+ function T.api.setstring_Sets_OnNewProperty()
+ premake.CurrentConfiguration = { }
+ premake.setstring("config", "myfield", "hello")
+ test.isequal("hello", premake.CurrentConfiguration.myfield)
+ end
+
+ function T.api.setstring_Overwrites_OnExistingProperty()
+ premake.CurrentConfiguration = { }
+ premake.CurrentConfiguration.myfield = "hello"
+ premake.setstring("config", "myfield", "goodbye")
+ test.isequal("goodbye", premake.CurrentConfiguration.myfield)
+ end
+
+ function T.api.setstring_RaisesError_OnInvalidValue()
+ premake.CurrentConfiguration = { }
+ ok, err = pcall(function () premake.setstring("config", "myfield", "bad", { "Good", "Better", "Best" }) end)
+ test.isfalse(ok)
+ end
+
+ function T.api.setstring_CorrectsCase_OnConstrainedValue()
+ premake.CurrentConfiguration = { }
+ premake.setstring("config", "myfield", "better", { "Good", "Better", "Best" })
+ test.isequal("Better", premake.CurrentConfiguration.myfield)
+ end
+
+
diff --git a/tests/test_path.lua b/tests/test_path.lua
index ab5531b..e19587c 100644
--- a/tests/test_path.lua
+++ b/tests/test_path.lua
@@ -93,6 +93,10 @@
test.isequal("d", path.getrelative("/a/b/c", "/a/b/c/d"))
end
+ function T.path.getrelative_ReturnsChildPath_OnWindowsAbsolute()
+ test.isequal("obj/debug", path.getrelative("C:/Code/Premake4", "C:/Code/Premake4/obj/debug"))
+ end
+
--
-- path.isabsolute() tests
diff --git a/tests/test_project.lua b/tests/test_project.lua
index f8e5cd8..7ffdb6f 100644
--- a/tests/test_project.lua
+++ b/tests/test_project.lua
@@ -1,5 +1,5 @@
--
--- tests/test_project.project.lua
+-- tests/test_project.lua
-- Automated test suite for the project support functions.
-- Copyright (c) 2008 Jason Perkins and the Premake project
--
@@ -12,202 +12,6 @@
_ACTION = "gmake"
result = ""
end
-
-
-
---
--- premake.checkprojects() tests
---
-
- function T.project.checkall_Succeeds_OnValidSession()
- solution "MySolution"
- configurations "Default"
- project "MyProject"
- kind "ConsoleApp"
- language "C"
-
- ok, err = premake.checkprojects()
- test.istrue( ok )
- end
-
-
- function T.project.checkall_Fails_OnNoConfigurations()
- solution "MySolution"
- project "MyProject"
-
- ok, err = premake.checkprojects()
- test.isfalse( ok )
- test.isequal("solution 'MySolution' needs configurations", err)
- end
-
-
- function T.project.checkall_Fails_OnNoProjectsInSolution()
- solution "MySolution"
- configurations "Default"
-
- ok, err = premake.checkprojects()
- test.isfalse( ok )
- test.isequal("solution 'MySolution' needs at least one project", err)
- end
-
-
- function T.project.checkall_Fails_OnNoLanguage()
- solution "MySolution"
- configurations "Default"
- project "MyProject"
- kind "ConsoleApp"
-
- ok, err = premake.checkprojects()
- test.isfalse( ok )
- test.isequal("project 'MyProject' needs a language", err)
- end
-
-
- function T.project.checkall_Fails_OnNoKind()
- solution "MySolution"
- language "C"
- configurations "Default"
- project "MyProject"
-
- ok, err = premake.checkprojects()
- test.isfalse( ok )
- test.isequal("project 'MyProject' needs a kind in configuration 'Default'", err)
- end
-
-
- function T.project.checkall_Fails_OnActionUnsupportedLanguage()
- solution "MySolution"
- configurations "Default"
- prj = project "MyProject"
- kind "ConsoleApp"
-
- prj.language = "XXX"
-
- ok, err = premake.checkprojects()
- test.isfalse(ok)
- test.isequal("the GNU Make action does not support XXX projects", err)
- end
-
-
- function T.project.checkall_Fails_OnActionUnsupportedKind()
- solution "MySolution"
- configurations "Default"
- prj = project "MyProject"
- language "C"
-
- prj.kind = "YYY"
-
- ok, err = premake.checkprojects()
- test.isfalse(ok)
- test.isequal("the GNU Make action does not support YYY projects", err)
- end
-
-
-
---
--- project.getobject() tests
---
-
- function T.project.getobject_RaisesError_OnNoContainer()
- premake.CurrentContainer = nil
- c, err = premake.getobject("container")
- test.istrue(c == nil)
- test.isequal("no active solution or project", err)
- end
-
- function T.project.getobject_RaisesError_OnNoActiveSolution()
- premake.CurrentContainer = { }
- c, err = premake.getobject("solution")
- test.istrue(c == nil)
- test.isequal("no active solution", err)
- end
-
- function T.project.getobject_RaisesError_OnNoActiveConfig()
- premake.CurrentConfiguration = nil
- c, err = premake.getobject("config")
- test.istrue(c == nil)
- test.isequal("no active solution, project, or configuration", err)
- end
-
-
---
--- premake.setstring() tests
---
-
- function T.project.setstring_Sets_OnNewProperty()
- premake.CurrentConfiguration = { }
- premake.setstring("config", "myfield", "hello")
- test.isequal("hello", premake.CurrentConfiguration.myfield)
- end
-
- function T.project.setstring_Overwrites_OnExistingProperty()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = "hello"
- premake.setstring("config", "myfield", "goodbye")
- test.isequal("goodbye", premake.CurrentConfiguration.myfield)
- end
-
- function T.project.setstring_RaisesError_OnInvalidValue()
- premake.CurrentConfiguration = { }
- ok, err = pcall(function () premake.setstring("config", "myfield", "bad", { "Good", "Better", "Best" }) end)
- test.isfalse(ok)
- end
-
- function T.project.setstring_CorrectsCase_OnConstrainedValue()
- premake.CurrentConfiguration = { }
- premake.setstring("config", "myfield", "better", { "Good", "Better", "Best" })
- test.isequal("Better", premake.CurrentConfiguration.myfield)
- end
-
-
---
--- premake.setarray() tests
---
-
- function T.project.setarray_Inserts_OnStringValue()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { }
- premake.setarray("config", "myfield", "hello")
- test.isequal("hello", premake.CurrentConfiguration.myfield[1])
- end
-
- function T.project.setarray_Inserts_OnTableValue()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { }
- premake.setarray("config", "myfield", { "hello", "goodbye" })
- test.isequal("hello", premake.CurrentConfiguration.myfield[1])
- test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
- end
-
- function T.project.setarray_Appends_OnNewValues()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { "hello" }
- premake.setarray("config", "myfield", "goodbye")
- test.isequal("hello", premake.CurrentConfiguration.myfield[1])
- test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
- end
-
- function T.project.setarray_FlattensTables()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { }
- premake.setarray("config", "myfield", { {"hello"}, {"goodbye"} })
- test.isequal("hello", premake.CurrentConfiguration.myfield[1])
- test.isequal("goodbye", premake.CurrentConfiguration.myfield[2])
- end
-
- function T.project.setarray_RaisesError_OnInvalidValue()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { }
- ok, err = pcall(function () premake.setarray("config", "myfield", "bad", { "Good", "Better", "Best" }) end)
- test.isfalse(ok)
- end
-
- function T.project.setarray_CorrectsCase_OnConstrainedValue()
- premake.CurrentConfiguration = { }
- premake.CurrentConfiguration.myfield = { }
- premake.setarray("config", "myfield", "better", { "Good", "Better", "Best" })
- test.isequal("Better", premake.CurrentConfiguration.myfield[1])
- end
--
diff --git a/tests/test_targets.lua b/tests/test_targets.lua
index 47e1040..b9c7cb2 100644
--- a/tests/test_targets.lua
+++ b/tests/test_targets.lua
@@ -247,7 +247,7 @@
function T.targets.TargetDir_OverridesBaseDir()
cfg.kind = "ConsoleApp"
cfg.targetdir = "MyTarget"
- test.isequal("MyTarget\\MyProject.exe", premake.gettarget(cfg, "build", "windows").fullpath)
+ test.isequal("MyTarget/MyProject.exe", premake.gettarget(cfg, "build", "windows").fullpath)
end
function T.targets.TargetExtension_OverridesDefault()
@@ -271,7 +271,7 @@
function T.targets.ImpLibDir_UsedOnSharedLinks()
cfg.kind = "SharedLib"
cfg.implibdir = "MyTarget"
- test.isequal("MyTarget\\MyProject.lib", premake.gettarget(cfg, "link", "windows").fullpath)
+ test.isequal("MyTarget/MyProject.lib", premake.gettarget(cfg, "link", "windows").fullpath)
end
function T.targets.ImpLibExtension_UsedOnSharedLinks()