This repository has been archived on 2022-12-23. You can view files and clone it, but cannot push or open issues or pull requests.
fuck-premake-old2/src/host/premake.c
2013-09-10 17:19:30 -04:00

404 lines
9.3 KiB
C
Executable File

/**
* \file premake.c
* \brief Program entry point.
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "premake.h"
#if PLATFORM_MACOSX
#include <CoreFoundation/CFBundle.h>
#endif
#define VERSION "HEAD"
#define COPYRIGHT "Copyright (C) 2002-2013 Jason Perkins and the Premake Project"
#define PROJECT_URL "https://bitbucket.org/premake/premake-stable/wiki"
#define ERROR_MESSAGE "%s\n"
static int process_arguments(lua_State* L, int argc, const char** argv);
static int process_option(lua_State* L, const char* arg);
static int load_builtin_scripts(lua_State* L);
int premake_locate(lua_State* L, const char* argv0);
/* A search path for script files */
static const char* scripts_path = NULL;
/* precompiled bytecode buffer; in bytecode.c */
extern const char* builtin_scripts[];
/* Built-in functions */
static const luaL_Reg path_functions[] = {
{ "getabsolute", path_getabsolute },
{ "getrelative", path_getrelative },
{ "isabsolute", path_isabsolute },
{ "join", path_join },
{ "translate", path_translate },
{ NULL, NULL }
};
static const luaL_Reg os_functions[] = {
{ "chdir", os_chdir },
{ "copyfile", os_copyfile },
{ "_is64bit", os_is64bit },
{ "isdir", os_isdir },
{ "getcwd", os_getcwd },
{ "getversion", os_getversion },
{ "isfile", os_isfile },
{ "matchdone", os_matchdone },
{ "matchisfile", os_matchisfile },
{ "matchname", os_matchname },
{ "matchnext", os_matchnext },
{ "matchstart", os_matchstart },
{ "mkdir", os_mkdir },
{ "pathsearch", os_pathsearch },
{ "rmdir", os_rmdir },
{ "stat", os_stat },
{ "uuid", os_uuid },
{ NULL, NULL }
};
static const luaL_Reg string_functions[] = {
{ "endswith", string_endswith },
{ "hash", string_hash },
{ NULL, NULL }
};
/**
* Initialize the Premake Lua environment.
*/
int premake_init(lua_State* L)
{
luaL_register(L, "path", path_functions);
luaL_register(L, "os", os_functions);
luaL_register(L, "string", string_functions);
/* push the application metadata */
lua_pushstring(L, LUA_COPYRIGHT);
lua_setglobal(L, "_COPYRIGHT");
lua_pushstring(L, VERSION);
lua_setglobal(L, "_PREMAKE_VERSION");
lua_pushstring(L, COPYRIGHT);
lua_setglobal(L, "_PREMAKE_COPYRIGHT");
lua_pushstring(L, PROJECT_URL);
lua_setglobal(L, "_PREMAKE_URL");
/* set the OS platform variable */
lua_pushstring(L, PLATFORM_STRING);
lua_setglobal(L, "_OS");
return OKAY;
}
int premake_execute(lua_State* L, int argc, const char** argv)
{
/* Parse the command line arguments */
int z = process_arguments(L, argc, argv);
/* Run the built-in Premake scripts */
if (z == OKAY) z = load_builtin_scripts(L);
return z;
}
/**
* Locate the Premake executable, and push its full path to the Lua stack.
* Based on:
* http://sourceforge.net/tracker/index.php?func=detail&aid=3351583&group_id=71616&atid=531880
* http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c
* http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
*/
int premake_locate(lua_State* L, const char* argv0)
{
#if !defined(PATH_MAX)
#define PATH_MAX (4096)
#endif
char buffer[PATH_MAX];
const char* path = NULL;
#if PLATFORM_WINDOWS
DWORD len = GetModuleFileName(NULL, buffer, PATH_MAX);
if (len > 0)
path = buffer;
#endif
#if PLATFORM_MACOSX
CFURLRef bundleURL = CFBundleCopyExecutableURL(CFBundleGetMainBundle());
CFStringRef pathRef = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
if (CFStringGetCString(pathRef, buffer, PATH_MAX - 1, kCFStringEncodingUTF8))
path = buffer;
#endif
#if PLATFORM_LINUX
int len = readlink("/proc/self/exe", buffer, PATH_MAX);
if (len > 0)
path = buffer;
#endif
#if PLATFORM_BSD
int len = readlink("/proc/curproc/file", buffer, PATH_MAX);
if (len < 0)
len = readlink("/proc/curproc/exe", buffer, PATH_MAX);
if (len > 0)
path = buffer;
#endif
#if PLATFORM_SOLARIS
int len = readlink("/proc/self/path/a.out", buffer, PATH_MAX);
if (len > 0)
path = buffer;
#endif
/* As a fallback, search the PATH with argv[0] */
if (!path)
{
lua_pushcfunction(L, os_pathsearch);
lua_pushstring(L, argv0);
lua_pushstring(L, getenv("PATH"));
if (lua_pcall(L, 2, 1, 0) == OKAY && !lua_isnil(L, -1))
{
lua_pushstring(L, "/");
lua_pushstring(L, argv0);
lua_concat(L, 3);
path = lua_tostring(L, -1);
}
}
/* If all else fails, use argv[0] as-is and hope for the best */
if (!path)
{
/* make it absolute, if needed */
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);
}
lua_pushstring(L, path);
return 1;
}
/**
* Process the command line arguments, splitting them into options, the
* target action, and any arguments to that action. The results are pushed
* into the session for later use. I could have done this in the scripts,
* but I need the value of the /scripts option to find them.
* \returns OKAY if successful.
*/
int process_arguments(lua_State* L, int argc, const char** argv)
{
int i;
/* Create empty lists for Options and Args */
lua_newtable(L);
lua_newtable(L);
for (i = 1; i < argc; ++i)
{
/* Options start with '/' or '--'. The first argument that isn't an option
* is the action. Anything after that is an argument to the action */
if (argv[i][0] == '/')
{
process_option(L, argv[i] + 1);
}
else if (argv[i][0] == '-' && argv[i][1] == '-')
{
process_option(L, argv[i] + 2);
}
else
{
/* not an option, is the action */
lua_pushstring(L, argv[i++]);
lua_setglobal(L, "_ACTION");
/* everything else is an argument */
while (i < argc)
{
lua_pushstring(L, argv[i++]);
lua_rawseti(L, -2, luaL_getn(L, -2) + 1);
}
}
}
/* push the Options and Args lists */
lua_setglobal(L, "_ARGS");
lua_setglobal(L, "_OPTIONS");
return OKAY;
}
/**
* Parse an individual command-line option.
* \returns OKAY if successful.
*/
int process_option(lua_State* L, const char* arg)
{
char key[512];
const char* value;
/* If a value is specified, split the option into a key/value pair */
char* ptr = strchr(arg, '=');
if (ptr)
{
int len = ptr - arg;
if (len > 511) len = 511;
strncpy(key, arg, len);
key[len] = '\0';
value = ptr + 1;
}
else
{
strcpy(key, arg);
value = "";
}
/* Make keys lowercase to avoid case issues */
for (ptr = key; *ptr; ++ptr) { *ptr = tolower(*ptr); }
/* Store it in the Options table, which is already on the stack */
lua_pushstring(L, value);
lua_setfield(L, -3, key);
/* The /scripts option gets picked up here to find the built-in scripts */
if (strcmp(key, "scripts") == 0 && strlen(value) > 0)
{
scripts_path = value;
}
return OKAY;
}
#if !defined(NDEBUG)
/**
* When running in debug mode, the scripts are loaded from the disk. The path to
* the scripts must be provided via either the /scripts command line option or
* the PREMAKE_PATH environment variable.
*/
int load_builtin_scripts(lua_State* L)
{
const char* filename;
/* call os.pathsearch() to locate _premake_main.lua */
lua_pushcfunction(L, os_pathsearch);
lua_pushstring(L, "_premake_main.lua");
lua_pushstring(L, scripts_path);
lua_pushstring(L, getenv("PREMAKE_PATH"));
lua_call(L, 3, 1);
if (lua_isnil(L, -1))
{
printf(ERROR_MESSAGE,
"Unable to find _premake_main.lua; use /scripts option when in debug mode!\n"
"Please refer to the documentation (or build in release mode instead)."
);
return !OKAY;
}
/* load the manifest, which includes all the required scripts */
scripts_path = lua_tostring(L, -1);
filename = lua_pushfstring(L, "%s/_manifest.lua", scripts_path);
if (luaL_dofile(L, filename))
{
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
lua_pushnil(L);
while (lua_next(L, -2))
{
filename = lua_pushfstring(L, "%s/%s", scripts_path, lua_tostring(L, -1));
if (luaL_dofile(L, filename)) {
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
lua_pop(L, 2);
}
lua_pop(L, 1);
/* run the bootstrapping script */
filename = lua_pushfstring(L, "%s/_premake_main.lua", scripts_path);
if (luaL_dofile(L, filename))
{
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
/* in debug mode, show full traceback on all errors */
lua_getglobal(L, "debug");
lua_getfield(L, -1, "traceback");
/* hand off control to the scripts */
lua_getglobal(L, "_premake_main");
if (lua_pcall(L, 0, 1, -2) != OKAY)
{
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
else
{
return (int)lua_tonumber(L, -1);
}
}
#endif
#if defined(NDEBUG)
/**
* When running in release mode, the scripts are loaded from a static data
* buffer, where they were stored by a preprocess. To update these embedded
* scripts, run `premake5 embed` then rebuild.
*/
int load_builtin_scripts(lua_State* L)
{
int i;
for (i = 0; builtin_scripts[i]; ++i)
{
if (luaL_dostring(L, builtin_scripts[i]) != OKAY)
{
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
}
/* hand off control to the scripts */
lua_getglobal(L, "_premake_main");
if (lua_pcall(L, 0, 1, 0) != OKAY)
{
printf(ERROR_MESSAGE, lua_tostring(L, -1));
return !OKAY;
}
else
{
return (int)lua_tonumber(L, -1);
}
}
#endif