From 55381d271bf005a5ffed33a4052c6277d34c8d98 Mon Sep 17 00:00:00 2001 From: g012 Date: Wed, 27 Sep 2017 01:33:21 +0200 Subject: [PATCH] Added CMake builder. --- CMakeLists.txt | 109 +++++++++++++++++++++++++++++++++++ embed.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++ l65.lua | 28 +++++++-- l65cfg.lua | 8 +++ l65cfg.lua.in | 8 +++ lfs.c | 16 ++---- lpeg.c | 3 + lua.h | 2 +- main.c | 70 ++++++++++++++++++++++- 9 files changed, 377 insertions(+), 19 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 embed.c create mode 100644 l65cfg.lua create mode 100644 l65cfg.lua.in diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3fbc573 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,109 @@ +cmake_minimum_required(VERSION 3.1) + +project(l65) + +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + +set(L65_SOURCE_DIR ${PROJECT_SOURCE_DIR}) +set(L65_BINARY_DIR ${PROJECT_BINARY_DIR}) + +set(L65_VERSION_MAJOR "1") +set(L65_VERSION_MINOR "0") +set(L65_VERSION_REVISION "0") +set(L65_VERSION "${L65_VERSION_MAJOR}.${L65_VERSION_MINOR}.${L65_VERSION_REVISION}") +configure_file("${L65_SOURCE_DIR}/l65cfg.lua.in" "${L65_BINARY_DIR}/l65cfg.lua") + +set(LINKLIBS) + +if (MSVC) + + set(USE_MSVC_RUNTIME_LIBRARY_DLL OFF CACHE BOOL "" FORCE) + + add_definitions(-D_HAS_EXCEPTIONS=0 -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE) + add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES) + add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS) + foreach (flag CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (${flag} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") + endif() + if (${flag} MATCHES "/MDd") + string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") + endif() + if(${flag} MATCHES "/EHsc") + string(REGEX REPLACE "/EHsc" "/EHs-c-" ${flag} "${${flag}}") + endif() + if(${flag} MATCHES "/GR") + string(REGEX REPLACE "/GR" "/GR-" ${flag} "${${flag}}") + endif() + if(${flag} MATCHES "/Gm") + string(REGEX REPLACE "/Gm" "/Gm-" ${flag} "${${flag}}") + endif() + endforeach() + + add_compile_options(/WX /MP /fp:fast /volatile:iso) + add_compile_options(/wd4103 /wd4244 /wd4456 /wd4554 /wd4557 /wd4702 /wd6255 /wd6262 /wd28278) + +else () + + if (APPLE) + add_definitions(-DLUA_USE_MACOSX) + else () + add_definitions(-DLUA_USE_LINUX) + endif () + + add_definitions(-D_FILE_OFFSET_BITS=64) + + add_compile_options(-fno-strict-aliasing -fomit-frame-pointer -ffast-math -fvisibility=hidden -fno-threadsafe-statics -fvisibility-inlines-hidden) + add_compile_options(-fno-rtti -fno-exceptions) + add_compile_options(-Werror -Wsign-compare -Wno-dangling-else -Wno-missing-braces -Wno-unused-function -Wno-shift-op-parentheses -Wno-unused-variable -Wno-switch -Wno-parentheses) + +endif() + +set(L65_SOURCES + ${L65_SOURCE_DIR}/lfs.c + ${L65_SOURCE_DIR}/lpeg.c + ${L65_SOURCE_DIR}/main.c + ) +set(L65_HEADERS + ${L65_SOURCE_DIR}/lua.h + ${L65_BINARY_DIR}/scripts.h + ) +set(L65_RESOURCES + ${L65_SOURCE_DIR}/6502.lua + ${L65_SOURCE_DIR}/l65.lua + ${L65_BINARY_DIR}/l65cfg.lua + ${L65_SOURCE_DIR}/vcs.l65 + ) + +add_executable(embed ${L65_SOURCE_DIR}/embed.c) +file(GLOB L65_FILES ${L65_SOURCE_DIR}/*.l65) +add_custom_command( + OUTPUT ${L65_BINARY_DIR}/scripts.h + COMMAND embed -o ${L65_BINARY_DIR}/scripts.h ${L65_SOURCE_DIR}/6502.lua ${L65_SOURCE_DIR}/l65.lua ${L65_BINARY_DIR}/l65cfg.lua ${L65_FILES} +) + +add_executable(${PROJECT_NAME} ${L65_SOURCES} ${L65_HEADERS} ${L65_RESOURCES}) + +set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) +target_include_directories(${PROJECT_NAME} PRIVATE "${L65_SOURCE_DIR}" "${L65_BINARY_DIR}") + +if (MSVC) + + set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/INCREMENTAL:NO /MANIFEST:NO /SUBSYSTEM:CONSOLE /ENTRY:mainCRTStartup") + +elseif (UNIX) + + list(APPEND LINKLIBS m dl) + +endif() + +target_link_libraries(${PROJECT_NAME} ${LINKLIBS}) diff --git a/embed.c b/embed.c new file mode 100644 index 0000000..dc5c4b5 --- /dev/null +++ b/embed.c @@ -0,0 +1,152 @@ +#define LUA_IMPLEMENTATION +#include "lua.h" + +#define PROGNAME "embed" /* default program name */ +#define OUTPUT "scripts.h" /* default output file */ + +static int dumping = 1; /* dump bytecodes? */ +static int stripping = 0; /* strip debug information? */ +static char Output[] = { OUTPUT }; /* default output file name */ +static const char* output = Output; /* actual output file name */ +static const char* progname = PROGNAME; /* actual program name */ + +static void fatal(const char* message) +{ + fprintf(stderr, "%s: %s\n", progname, message); + exit(EXIT_FAILURE); +} + +static void cannot(const char* what) +{ + fprintf(stderr, "%s: cannot %s %s: %s\n", progname, what, output, strerror(errno)); + exit(EXIT_FAILURE); +} + +static void usage(const char* message) +{ + if (*message == '-') + fprintf(stderr, "%s: unrecognized option '%s'\n", progname, message); + else + fprintf(stderr, "%s: %s\n", progname, message); + fprintf(stderr, + "usage: %s [options] [filenames]\n" + "Available options are:\n" + " -o name output to file 'name' (default is \"%s\")\n" + , progname, Output); + exit(EXIT_FAILURE); +} + +#define IS(s) (strcmp(argv[i],s)==0) + +static int doargs(int argc, char* argv[]) +{ + int i; + if (argv[0] != NULL && *argv[0] != 0) progname = argv[0]; + for (i = 1; i < argc; i++) + { + if (*argv[i] != '-') /* end of options; keep it */ + break; + else if (IS("--")) /* end of options; skip it */ + { + ++i; + break; + } + else if (IS("-")) /* end of options; use stdin */ + break; + else if (IS("-o")) /* output file */ + { + output = argv[++i]; + if (output == NULL || *output == 0 || (*output == '-' && output[1] != 0)) + usage("'-o' needs argument"); + if (IS("-")) output = NULL; + } + else /* unknown option */ + usage(argv[i]); + } + return i; +} + +#define FUNCTION "(function()end)();" + +static int w_o; +static int writer(lua_State* L, const void* p, size_t size, void* f) +{ + for (size_t i = 0; i < size; ++i) + { + if ((i+w_o) % 32 == 0) fprintf(f, "\n"); + fprintf(f, "0x%02X, ", (int)(((unsigned char*)p)[i])); + } + w_o += size; + return size == 0; +} + +static int pmain(lua_State* L) +{ + int argc = (int)lua_tointeger(L, 1); + char** argv = (char**)lua_touserdata(L, 2); + int i; + if (!lua_checkstack(L, argc)) fatal("too many input files"); + FILE* f = (output == NULL) ? stdout : fopen(output, "wb"); + if (f == NULL) cannot("open"); + for (i = 0; i < argc; i++) + { + int compile = 0; + const char* filename = IS("-") ? NULL : argv[i]; + if (!filename) fatal("invalid input file"); + char *ufname = strdup(filename); + int fnix = 0; for (int i = 0; ufname[i]; ++i) { if (ufname[i] == '/' || ufname[i] == '\\') fnix = i + 1; if (ufname[i] == '.') ufname[i] = '_'; } + char *name = malloc(1024); + sprintf(name, "script_%s", ufname + fnix); + free(ufname); + int fnl = strlen(filename); + compile = fnl > 4 && !strcmp(".lua", filename + fnl - 4); + if (compile) + { + if (luaL_loadfile(L, filename) != LUA_OK) fatal(lua_tostring(L, -1)); + fprintf(f, "static const unsigned char %s[] = {", name); + w_o = 0; + lua_dump(L, writer, f, 0); + lua_pop(L, 1); + fprintf(f, "\n};\n"); + } + else + { + FILE* l = fopen(filename, "rb"); if (!l) cannot("open"); + fseek(l, 0, SEEK_END); + int size = (int)ftell(l); + rewind(l); + unsigned char *buffer = malloc(size); + if (size != fread(buffer, 1, size, l)) fatal("failed reading input file"); + fclose(l); + fprintf(f, "static const char %s[] = {", name); + for (int i = 0; i < size; ++i) + { + if (i % 32 == 0) fprintf(f, "\n"); + fprintf(f, "0x%02X, ", (int)buffer[i]); + } + fprintf(f, "\n};\n"); + free(buffer); + } + free(name); + } + if (ferror(f)) cannot("write"); + if (fclose(f)) cannot("close"); + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + int i = doargs(argc, argv); + argc -= i; argv += i; + if (argc <= 0) usage("no input files given"); + L = luaL_newstate(); + if (L == NULL) fatal("cannot create state: not enough memory"); + lua_pushcfunction(L, &pmain); + lua_pushinteger(L, argc); + lua_pushlightuserdata(L, argv); + if (lua_pcall(L, 2, 0, 0) != LUA_OK) fatal(lua_tostring(L, -1)); + lua_close(L); + return EXIT_SUCCESS; +} + diff --git a/l65.lua b/l65.lua index 1ac2353..e2048a1 100644 --- a/l65.lua +++ b/l65.lua @@ -2478,15 +2478,31 @@ l65 = { loadfile_org = loadfile, dofile_org = dofile, } +do + local getembedded = type(arg[-1]) == 'function' and arg[-1] + l65.load_embedded = function(name) + if not getembedded then return end + local src,isl65 = getembedded(name) + if not src then return end + if isl65 then + local filename = name .. '.l65' + local st, ast = assert(l65.parse(src)) + local bc = assert(l65.load_org(l65.format(ast), filename)) + return bc, filename + else + local filename = name .. '.lua' + local bc = assert(l65.load_org(src, filename)) + return bc, filename + end + end +end l65.searcher = function(name) local filename,err = package.searchpath(name, l65.search_path, '.', '.') if not filename then return err end - local file = io.open(filename, 'rb') - if not file then return "failed to open " .. filename .. " for reading" end + local file = assert(io.open(filename, 'rb')) local src = file:read('*a') file:close() - local st, ast = l65.parse(src) - if not st then print(ast) return end + local st, ast = assert(l65.parse(src)) local bc = assert(l65.load_org(l65.format(ast), filename)) return bc, filename end @@ -2543,6 +2559,7 @@ l65.uninstallhooks = function() dofile = l65.dofile_org end end +table.insert(package.searchers, l65.searcher_index, l65.load_embedded) l65.installhooks() function getopt(optstring, ...) @@ -2578,8 +2595,9 @@ function getopt(optstring, ...) end) end +local cfg=require"l65cfg" l65.cfg=cfg local version = function() - print("1.0.0") + print(string.format("l65 %s", cfg.version)) end local usage = function() print(string.format([[ diff --git a/l65cfg.lua b/l65cfg.lua new file mode 100644 index 0000000..cbf9973 --- /dev/null +++ b/l65cfg.lua @@ -0,0 +1,8 @@ +local M = {} + +M.major = 1 +M.minor = 0 +M.revision = 0 +M.version = "1.0.0" + +return M diff --git a/l65cfg.lua.in b/l65cfg.lua.in new file mode 100644 index 0000000..a1ac548 --- /dev/null +++ b/l65cfg.lua.in @@ -0,0 +1,8 @@ +local M = {} + +M.major = ${L65_VERSION_MAJOR} +M.minor = ${L65_VERSION_MINOR} +M.revision = ${L65_VERSION_REVISION} +M.version = "${L65_VERSION}" + +return M diff --git a/lfs.c b/lfs.c index fe018b9..d3bf64b 100644 --- a/lfs.c +++ b/lfs.c @@ -2,6 +2,8 @@ * lfs.c and lfs.h mixed together */ +#include "lua.h" + /* ** LuaFileSystem ** Copyright Kepler Project 2003 - 2016 (http://keplerproject.github.io/luafilesystem) @@ -16,9 +18,9 @@ #endif #ifdef _WIN32 - #define chdir(p) (_chdir(p)) - #define getcwd(d, s) (_getcwd(d, s)) - #define rmdir(p) (_rmdir(p)) + //#define chdir(p) (_chdir(p)) + //#define getcwd(d, s) (_getcwd(d, s)) + //#define rmdir(p) (_rmdir(p)) #define LFS_EXPORT __declspec (dllexport) #ifndef fileno #define fileno(f) (_fileno(f)) @@ -102,12 +104,6 @@ LFS_EXPORT int luaopen_lfs (lua_State *L); #define LFS_MAXPATHLEN MAXPATHLEN #endif -//#include -//#include -//#include - -//#include "lfs.h" - #define LFS_VERSION "1.6.3" #define LFS_LIBNAME "lfs" @@ -325,7 +321,7 @@ static int lfs_lock_dir(lua_State *L) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; } strcpy(ln, path); strcat(ln, lockfile); - if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW, + if((fd = CreateFileA(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) { int en = GetLastError(); free(ln); lua_pushnil(L); diff --git a/lpeg.c b/lpeg.c index 6535482..44e3e9d 100644 --- a/lpeg.c +++ b/lpeg.c @@ -7,6 +7,7 @@ #include #include #include +#include "lua.h" // only exported function int luaopen_lpeg (lua_State *L); @@ -25,8 +26,10 @@ int luaopen_lpeg (lua_State *L); #if !defined(LPEG_DEBUG) +#ifndef NDEBUG #define NDEBUG #endif +#endif #define VERSION "1.0.1" diff --git a/lua.h b/lua.h index a27bef4..3393b27 100644 --- a/lua.h +++ b/lua.h @@ -13930,7 +13930,7 @@ static int luai_searcherpreload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ - lua_pushfstring(L, "\n\tno luai_field package.preload['%s']", name); + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } diff --git a/main.c b/main.c index 0ea8a62..488804f 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,79 @@ #define LUA_IMPLEMENTATION #include "lua.h" +#include "scripts.h" extern int luaopen_lpeg(lua_State *L); extern int luaopen_lfs(lua_State *L); +static struct script { const char *name; int t; const char *data; size_t sz; } embedded[] = { + { "l65cfg", 0, script_l65cfg_lua, sizeof(script_l65cfg_lua) }, + { "vcs", 1, script_vcs_l65, sizeof(script_vcs_l65) }, +}; + +static int getembedded(lua_State *L) +{ + const char *name = lua_tostring(L, 1); + for (struct script *s = embedded, *e = s + sizeof(embedded) / sizeof(embedded[0]); s != e; ++s) + { + if (!strcmp(s->name, name)) + { + lua_pushlstring(L, s->data, s->sz); + lua_pushboolean(L, s->t); + return 2; + } + } + return 0; +} + +static int msghandler(lua_State *L) +{ + const char *msg = lua_tostring(L, 1); + if (msg == NULL) + { + if (luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING) + return 1; + msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); + return 1; +} + int main(int argc, char *argv[]) { lua_State *L = luaL_newstate(); luaL_openlibs(L); - luaL_require(L, "lpeg", luaopen_lpeg, 1); lua_pop(L, 1); - luaL_require(L, "lfs", luaopen_lfs, 1); lua_pop(L, 1); - return 0; + luaL_requiref(L, "lpeg", luaopen_lpeg, 1); lua_pop(L, 1); + luaL_requiref(L, "lfs", luaopen_lfs, 1); lua_pop(L, 1); + + // preload embedded lua scripts + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + luaL_loadbufferx(L, script_6502_lua, sizeof(script_6502_lua), "6502.lua", "b"); + lua_setfield(L, -2, "6502"); + lua_pop(L, 1); + + // error handler + lua_pushcfunction(L, msghandler); + // l65.lua script + luaL_loadbufferx(L, script_l65_lua, sizeof(script_l65_lua), "l65.lua", "b"); + // arg[] table + lua_createtable(L, argc-1, 2); + lua_pushcfunction(L, getembedded); // pass embedded script lookup function as arg[-1] + lua_rawseti(L, -2, -1); + for (int i = 0; i < argc; i++) lua_pushstring(L, argv[i]), lua_rawseti(L, -2, i); + lua_pushvalue(L, -1); + lua_setglobal(L, "arg"); + // ... arguments + { int i; for (i = 1; i < argc; ++i) lua_rawgeti(L, -i, i); lua_remove(L, -i); } + // call l65 + int status = lua_pcall(L, argc-1, 0, -argc-1); + if (status != LUA_OK) + { + const char *msg = lua_tostring(L, -1); + fprintf(stderr, "%s\n", msg); + lua_pop(L, 1); + } + lua_pop(L, 1); // remove msghandler + lua_close(L); + return status; }