diff --git a/LICENSE.txt b/LICENSE.txt index 5b63164a..ea228196 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2003-2012 Jason Perkins and individual contributors. +Copyright (c) 2003-2013 Jason Perkins and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/README.txt b/README.txt index 8e1d2b7b..6ade58c3 100644 --- a/README.txt +++ b/README.txt @@ -1,7 +1,7 @@ PREMAKE A build configuration tool - Copyright (C) 2002-2012 by Jason Perkins + Copyright (C) 2002-2013 by Jason Perkins Distributed under the terms of the BSD License, see LICENSE.txt The Lua language and runtime library is (C) TeCGraf, PUC-Rio. diff --git a/src/base/action.lua b/src/base/action.lua index 6becbdb5..f2693580 100644 --- a/src/base/action.lua +++ b/src/base/action.lua @@ -12,14 +12,14 @@ -- premake.action.list = { } - + -- -- Register a new action. -- -- @param a -- The new action object. --- +-- function premake.action.add(a) -- validate the action object, at least a little bit @@ -29,13 +29,13 @@ missing = field end end - + if (missing) then error("action needs a " .. missing, 3) end -- add it to the master list - premake.action.list[a.trigger] = a + premake.action.list[a.trigger] = a end @@ -51,36 +51,23 @@ function premake.action.call(name) local a = premake.action.list[name] - -- a bit of a hack, but check for the new next-gen actions, and - -- translate things accordingly. I'll yank this once the next-gen - -- actions are done and official - if a.isnextgen then - if _ACTION:endswith("ng") then - _ACTION = _ACTION:sub(1, -3) + -- TODO: remove this once everyone's had a chance to see + -- the deprecation warning + if _ACTION:endswith("ng") then + _ACTION = _ACTION:sub(1, -3) + end + + for sln in premake.solution.each() do + if a.onsolution then + a.onsolution(sln) end - for sln in premake.solution.each() do - if a.onsolution then - a.onsolution(sln) - end - for prj in premake.solution.eachproject_ng(sln) do - if a.onproject and not prj.external then - a.onproject(prj) - end - end - end - else - for sln in premake.solution.each() do - if a.onsolution then - a.onsolution(sln) - end - for prj in premake.solution.eachproject(sln) do - if a.onproject and not prj.external then - a.onproject(prj) - end + for prj in premake.solution.eachproject_ng(sln) do + if a.onproject and not prj.external then + a.onproject(prj) end end end - + if a.execute then a.execute() end @@ -97,8 +84,8 @@ function premake.action.current() return premake.action.get(_ACTION) end - - + + -- -- Retrieve an action by name. -- @@ -129,7 +116,7 @@ table.insert(keys, action.trigger) end table.sort(keys) - + local i = 0 return function() i = i + 1 @@ -147,7 +134,7 @@ function premake.action.set(name) _ACTION = name - + -- Some actions imply a particular operating system local action = premake.action.get(name) if action then @@ -195,11 +182,11 @@ if not action then return false end - + if action.supportsconfig then return action.supportsconfig(cfg) end - + return true end diff --git a/src/base/path.lua b/src/base/path.lua index dbc0749e..98de6835 100644 --- a/src/base/path.lua +++ b/src/base/path.lua @@ -1,7 +1,7 @@ -- -- path.lua -- Path manipulation functions. --- Copyright (c) 2002-2012 Jason Perkins and the Premake project +-- Copyright (c) 2002-2013 Jason Perkins and the Premake project -- @@ -17,17 +17,17 @@ p = p:sub(1, -2) endquote = '"' end - + -- add the extension if it isn't there already if not p:endswith(ext) then p = p .. ext end - + -- put the quote back if necessary if endquote then p = p .. endquote end - + return p end @@ -36,7 +36,7 @@ -- Get the absolute file path from a relative path. The requested -- file path doesn't actually need to exist. -- - + function path.getabsolute(p) if type(p) == "table" then local result = {} @@ -45,11 +45,11 @@ end return result end - + -- normalize the target path p = path.translate(p, "/") if (p == "") then p = "." end - + -- if the directory is already absolute I don't need to do anything local result = iif (path.isabsolute(p), nil, os.getcwd()) @@ -69,13 +69,13 @@ end end end - + -- if I end up with a trailing slash remove it result = iif(result:endswith("/"), result:sub(1, -2), result) - + return result end - + -- -- Retrieve the filename portion of a path, without any extension. @@ -90,10 +90,10 @@ return name end end - - + + -- --- Retrieve the directory portion of a path, or an empty string if +-- Retrieve the directory portion of a path, or an empty string if -- the path does not include a directory. -- @@ -134,9 +134,9 @@ return "" end end - - - + + + -- -- Retrieve the filename portion of a path. -- @@ -149,8 +149,8 @@ return p end end - - + + -- -- Returns the relative path from src to dest. -- @@ -164,13 +164,13 @@ if (src == dst) then return "." end - + -- dollar macro? Can't tell what the real path is; use absolute -- This enables paths like $(SDK_ROOT)/include to work correctly. if dst:startswith("$") then return dst end - + src = src .. "/" dst = dst .. "/" @@ -188,19 +188,19 @@ break end end - + -- if they have nothing in common return absolute path local first = src:find("/", 0, true) if idx <= first then return dst:sub(1, -2) end - - -- trim off the common directories from the front + + -- trim off the common directories from the front src = src:sub(idx + 1) dst = dst:sub(idx + 1) - + -- back up from dst to get to this common parent - local result = "" + local result = "" idx = src:find("/") while (idx) do result = result .. "../" @@ -213,7 +213,7 @@ -- remove the trailing slash return result:sub(1, -2) end - + -- -- Returns true if the filename has a particular extension. @@ -248,11 +248,11 @@ function path.iscfile(fname) return path.hasextension(fname, { ".c", ".s", ".m" }) end - + function path.iscppfile(fname) return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" }) end - + function path.iscppheader(fname) return path.hasextension(fname, { ".h", ".hh", ".hpp", ".hxx" }) end @@ -286,41 +286,6 @@ return path.hasextension(fname, ".rc") end - --- --- Join one or more pieces of a path together into a single path. --- --- @param ... --- One or more path strings. --- @return --- The joined path. --- - - function path.join(...) - local numargs = select("#", ...) - if numargs == 0 then - return ""; - end - - local allparts = {} - for i = numargs, 1, -1 do - local part = select(i, ...) - if part and #part > 0 and part ~= "." then - -- trim off trailing slashes - while part:endswith("/") do - part = part:sub(1, -2) - end - - table.insert(allparts, 1, part) - if path.isabsolute(part) then - break - end - end - end - - return table.concat(allparts, "/") - end - -- -- Takes a path which is relative to one location and makes it relative @@ -332,15 +297,15 @@ p = path.getrelative(newbase, p) return p end - - + + -- -- Convert the separators in a path from one form to another. If `sep` --- is nil, then a Windows-style backslash is used (since those are +-- is nil, then a Windows-style backslash is used (since those are -- likely the only paths needing translating). -- - function path.translate(p, sep) + function path.translate(p, sep) if type(p) == "table" then local result = { } for _, value in ipairs(p) do @@ -375,10 +340,10 @@ -- have competing star replacements to worry about pattern = pattern:gsub("%*%*", "\001") pattern = pattern:gsub("%*", "\002") - + -- Replace the placeholders with their Lua patterns pattern = pattern:gsub("\001", ".*") pattern = pattern:gsub("\002", "[^/]*") - + return pattern end diff --git a/src/host/path_isabsolute.c b/src/host/path_isabsolute.c index 0959ede8..74129357 100644 --- a/src/host/path_isabsolute.c +++ b/src/host/path_isabsolute.c @@ -1,25 +1,27 @@ /** * \file path_isabsolute.c * \brief Determines if a path is absolute or relative. - * \author Copyright (c) 2002-2012 Jason Perkins and the Premake project + * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project */ #include "premake.h" int path_isabsolute(lua_State* L) -{ const char* path = luaL_checkstring(L, -1); - if (path[0] == '/' || - path[0] == '\\' || - path[0] == '$' || - (path[0] == '"' && path[1] == '$') || - (path[0] != '\0' && path[1] == ':')) - { - lua_pushboolean(L, 1); - return 1; - } - else - { - return 0; - } +{ + const char* path = luaL_checkstring(L, -1); + lua_pushboolean(L, do_isabsolute(path)); + return 1; +} + + +int do_isabsolute(const char* path) +{ + return ( + path[0] == '/' || + path[0] == '\\' || + path[0] == '$' || + (path[0] == '"' && path[1] == '$') || + (path[0] != '\0' && path[1] == ':') + ); } diff --git a/src/host/path_join.c b/src/host/path_join.c new file mode 100644 index 00000000..c0a17bfb --- /dev/null +++ b/src/host/path_join.c @@ -0,0 +1,57 @@ +/** + * \file path_join.c + * \brief Join two or more pieces of a file system path. + * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project + */ + +#include "premake.h" +#include + + +int path_join(lua_State* L) +{ + int i; + char buffer[0x4000]; + char* ptr = buffer; + + /* for each argument... */ + int argc = lua_gettop(L); + for (i = 1; i <= argc; ++i) { + /* if next argument is nil, skip it */ + if (lua_isnil(L, i)) { + continue; + } + + /* grab the next argument */ + const char* part = luaL_checkstring(L, i); + int len = strlen(part); + + /* remove trailing slashes */ + while (len > 1 && part[len - 1] == '/') { + --len; + } + + /* ignore empty segments and "." */ + if (len == 0 || (len == 1 && part[0] == '.')) { + continue; + } + + /* if I encounter an absolute path, restart my result */ + if (do_isabsolute(part)) { + ptr = buffer; + } + + /* if the path is already started, split parts */ + if (ptr != buffer && *(ptr - 1) != '/') { + *(ptr++) = '/'; + } + + /* append new part */ + strcpy(ptr, part); + ptr += len; + } + + *ptr = '\0'; + lua_pushstring(L, buffer); + return 1; +} diff --git a/src/host/premake.c b/src/host/premake.c index 21ddbfcc..9a693412 100755 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -1,7 +1,7 @@ /** * \file premake.c * \brief Program entry point. - * \author Copyright (c) 2002-2012 Jason Perkins and the Premake project + * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project */ #include @@ -36,6 +36,7 @@ extern const char* builtin_scripts[]; /* Built-in functions */ static const luaL_Reg path_functions[] = { { "isabsolute", path_isabsolute }, + { "join", path_join }, { NULL, NULL } }; @@ -89,7 +90,7 @@ int premake_init(lua_State* L) /* set the OS platform variable */ lua_pushstring(L, PLATFORM_STRING); lua_setglobal(L, "_OS"); - + return OKAY; } @@ -101,7 +102,7 @@ int premake_execute(lua_State* L, int argc, const char** argv) /* Run the built-in Premake scripts */ if (z == OKAY) z = load_builtin_scripts(L); - + return z; } @@ -177,14 +178,14 @@ int premake_locate(lua_State* L, const char* argv0) os_getcwd(L); lua_pushstring(L, "/"); lua_pushstring(L, argv0); - + if (!path_isabsolute(L)) { lua_concat(L, 3); } else { lua_pop(L, 1); } - + path = lua_tostring(L, -1); } diff --git a/src/host/premake.h b/src/host/premake.h index a22acad9..88131217 100755 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -1,7 +1,7 @@ /** * \file premake.h * \brief Program-wide constants and definitions. - * \author Copyright (c) 2002-2011 Jason Perkins and the Premake project + * \author Copyright (c) 2002-2013 Jason Perkins and the Premake project */ #define lua_c @@ -48,11 +48,13 @@ /* Bootstrapping helper functions */ unsigned long do_hash(const char* str, int seed); +int do_isabsolute(const char* path); int do_isfile(const char* filename); /* Built-in functions */ int path_isabsolute(lua_State* L); +int path_join(lua_State* L); int os_chdir(lua_State* L); int os_copyfile(lua_State* L); int os_getcwd(lua_State* L); diff --git a/tests/base/test_path.lua b/tests/base/test_path.lua index dd049b38..7fa52e3f 100644 --- a/tests/base/test_path.lua +++ b/tests/base/test_path.lua @@ -4,8 +4,7 @@ -- Copyright (c) 2008-2010 Jason Perkins and the Premake project -- - T.path = { } - local suite = T.path + local suite = test.declare("path") -- @@ -24,30 +23,30 @@ function suite.getabsolute_RemovesDotDots_OnPosixAbsolute() test.isequal("/ProjectB/bin", path.getabsolute("/ProjectA/../ProjectB/bin")) end - + function suite.getabsolute_OnTrailingSlash() local expected = path.translate(os.getcwd(), "/") .. "/a/b/c" test.isequal(expected, path.getabsolute("a/b/c/")) end - + function suite.getabsolute_OnLeadingEnvVar() test.isequal("$(HOME)/user", path.getabsolute("$(HOME)/user")) end - + function suite.getabsolute_OnMultipleEnvVar() test.isequal("$(HOME)/$(USER)", path.getabsolute("$(HOME)/$(USER)")) end - + function suite.getabsolute_OnTrailingEnvVar() local expected = path.translate(os.getcwd(), "/") .. "/home/$(USER)" test.isequal(expected, path.getabsolute("home/$(USER)")) end - + function suite.getabsolute_OnLeadingEnvVarQuoted() test.isequal('"$(HOME)/user"', path.getabsolute('"$(HOME)/user"')) end - - + + -- -- path.getbasename() tests -- @@ -64,11 +63,11 @@ function suite.getdirectory_ReturnsEmptyString_OnNoDirectory() test.isequal(".", path.getdirectory("filename.ext")) end - + function suite.getdirectory_ReturnsDirectory_OnSingleLevelPath() test.isequal("dir0", path.getdirectory("dir0/filename.ext")) end - + function suite.getdirectory_ReturnsDirectory_OnMultiLeveLPath() test.isequal("dir0/dir1/dir2", path.getdirectory("dir0/dir1/dir2/filename.ext")) end @@ -76,7 +75,7 @@ function suite.getdirectory_ReturnsRootPath_OnRootPathOnly() test.isequal("/", path.getdirectory("/filename.ext")) end - + -- @@ -86,13 +85,13 @@ function suite.getdrive_ReturnsNil_OnNotWindows() test.isnil(path.getdrive("/hello")) end - + function suite.getdrive_ReturnsLetter_OnWindowsAbsolute() test.isequal("x", path.getdrive("x:/hello")) end - - - + + + -- -- path.getextension() tests -- @@ -104,19 +103,19 @@ function suite.getextension_ReturnsExtension() test.isequal(".txt", path.getextension("filename.txt")) end - + function suite.getextension_OnMultipleDots() test.isequal(".txt", path.getextension("filename.mod.txt")) end - + function suite.getextension_OnLeadingNumeric() test.isequal(".7z", path.getextension("filename.7z")) end - + function suite.getextension_OnUnderscore() test.isequal(".a_c", path.getextension("filename.a_c")) end - + function suite.getextension_OnHyphen() test.isequal(".a-c", path.getextension("filename.a-c")) end @@ -134,7 +133,7 @@ function suite.getrelative_ReturnsDoubleDot_OnChildToParent() test.isequal("..", path.getrelative("/a/b/c", "/a/b")) end - + function suite.getrelative_ReturnsDoubleDot_OnSiblingToSibling() test.isequal("../d", path.getrelative("/a/b/c", "/a/b/d")) end @@ -146,19 +145,19 @@ function suite.getrelative_ReturnsChildPath_OnWindowsAbsolute() test.isequal("obj/debug", path.getrelative("C:/Code/Premake4", "C:/Code/Premake4/obj/debug")) end - + function suite.getrelative_ReturnsAbsPath_OnDifferentDriveLetters() test.isequal("D:/Files", path.getrelative("C:/Code/Premake4", "D:/Files")) end - + function suite.getrelative_ReturnsAbsPath_OnDollarMacro() test.isequal("$(SDK_HOME)/include", path.getrelative("C:/Code/Premake4", "$(SDK_HOME)/include")) end - + function suite.getrelative_ReturnsAbsPath_OnRootedPath() test.isequal("/opt/include", path.getrelative("/home/me/src/project", "/opt/include")) end - + -- -- path.isabsolute() tests @@ -175,7 +174,7 @@ function suite.isabsolute_ReturnsFalse_OnRelativePath() test.isfalse(path.isabsolute("a/b/c")) end - + function suite.isabsolute_ReturnsTrue_OnDollarSign() test.istrue(path.isabsolute("$(SDK_HOME)/include")) end @@ -188,11 +187,11 @@ function suite.join_OnValidParts() test.isequal("p1/p2", path.join("p1", "p2")) end - + function suite.join_OnAbsoluteUnixPath() test.isequal("/p2", path.join("p1", "/p2")) end - + function suite.join_OnAbsoluteWindowsPath() test.isequal("C:/p2", path.join("p1", "C:/p2")) end @@ -200,11 +199,11 @@ function suite.join_OnCurrentDirectory() test.isequal("p2", path.join(".", "p2")) end - + function suite.join_OnNilSecondPart() test.isequal("p1", path.join("p1", nil)) end - + function suite.join_onMoreThanTwoParts() test.isequal("p1/p2/p3", path.join("p1", "p2", "p3")) end @@ -225,6 +224,10 @@ test.isequal("p2", path.join("", "p2", "")) end + function suite.join_canJoinBareSlash() + test.isequal("/Users", path.join("/", "Users")) + end + -- -- path.rebase() tests @@ -272,7 +275,7 @@ function suite.wildcards_escapeStar() test.isequal("vs[^/]*", path.wildcards("vs*")) end - + function suite.wildcards_escapeStarStar() test.isequal("Images/.*%.bmp", path.wildcards("Images/**.bmp")) end diff --git a/tests/stress b/tests/stress old mode 100644 new mode 100755 index b42c2575..420b0f81 --- a/tests/stress +++ b/tests/stress @@ -1,2 +1,2 @@ #!/bin/sh -../bin/debug/premake4 /scripts=../src /file=test_stress.lua vs2008 +../bin/debug/premake4 /scripts=../src /file=test_stress.lua stress diff --git a/tests/test_stress.lua b/tests/test_stress.lua index c51e1305..86f61343 100644 --- a/tests/test_stress.lua +++ b/tests/test_stress.lua @@ -1,44 +1,58 @@ -- -- tests/tests_stress.lua -- Stress test for Premake. --- Copyright (c) 2009 Jason Perkins and the Premake project +-- Copyright (c) 2009, 2013 Jason Perkins and the Premake project -- -local numprojects = 100 -local numfiles = 100 +local numprojects = 5 +local numfiles = 100 +local numbuildcfgs = 4 +local numplatforms = 6 + dofile("pepperfish_profiler.lua") profiler = newProfiler() -function dumpresults(sorttotal) - local outfile = io.open("build/profile.txt", "w+" ) - profiler:report(outfile, sorttotal) - outfile:close() -end +profiler:start() solution "MySolution" - configurations { "Debug", "Release", "DebugDLL", "ReleaseDLL" } - platforms { "Native", "x32", "x64" } location "build" - - configuration "Debug" - defines { "_DEBUG" } - flags { "Symbols" } - - configuration "Release" - defines { "NDEBUG" } - flags { "Optimize" } - + + for i = 1, numbuildcfgs do + configurations ( "BuildCfg" .. i ) + end + + for i = 1, numplatforms do + platforms ( "Platform" .. i ) + end + for pi = 1, numprojects do - + project ("Project" .. pi) location "build" kind "ConsoleApp" language "C++" - + for fi = 1, numfiles do files { "file" .. fi .. ".cpp" } end - + end + + +newaction +{ + trigger = "stress", + description = "Run a stress test", + execute = function() + _ACTION = "vs2008" + premake.action.call(_ACTION) + + profiler:stop() + + local outfile = io.open("build/profile.txt", "w+" ) + profiler:report(outfile) + outfile:close() + end +}