diff options
author | starkos <unknown> | 2008-12-15 18:00:35 +0300 |
---|---|---|
committer | starkos <unknown> | 2008-12-15 18:00:35 +0300 |
commit | b57df3a428069f854bf388a5e4181806fe7a92e7 (patch) | |
tree | ac34f2207f0e11b89165c702bba12a7d47901583 | |
parent | 548cf91fd5121890592928c8a1da4bcf954d7e14 (diff) |
** Merged GMake C# support from branches/csharp (r630:648)
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 Binary files differnew file mode 100644 index 0000000..73fe985 --- /dev/null +++ b/samples/project/CsConsoleApp/Crate.bmp 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('&', "&") - value = value:gsub('"', """) - value = value:gsub("'", "'") - value = value:gsub('<', "<") - value = value:gsub('>', ">") - value = value:gsub('\r', "
") - value = value:gsub('\n', "
") - 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('&', "&") + value = value:gsub('"', """) + value = value:gsub("'", "'") + value = value:gsub('<', "<") + value = value:gsub('>', ">") + value = value:gsub('\r', "
") + value = value:gsub('\n', "
") + 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() |