From d9d3c714351b82cfd387fc6f83d89591909312a2 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 9 Jul 2009 15:04:27 +0000 Subject: [PATCH] libs: introduce lmo - Lua Machine Objects, an implementation of binary hash tables --- libs/lmo/Makefile | 46 +++++++++ libs/lmo/src/lmo.h | 72 +++++++++++++++ libs/lmo/src/lmo_core.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++ libs/lmo/src/lmo_hash.c | 53 +++++++++++ libs/lmo/src/lmo_lookup.c | 58 ++++++++++++ libs/lmo/src/lmo_lualib.c | 124 +++++++++++++++++++++++++ libs/lmo/src/lmo_lualib.h | 33 +++++++ libs/lmo/src/lmo_po2lmo.c | 199 +++++++++++++++++++++++++++++++++++++++ libs/lmo/standalone.mk | 56 +++++++++++ 9 files changed, 872 insertions(+) create mode 100644 libs/lmo/Makefile create mode 100644 libs/lmo/src/lmo.h create mode 100644 libs/lmo/src/lmo_core.c create mode 100644 libs/lmo/src/lmo_hash.c create mode 100644 libs/lmo/src/lmo_lookup.c create mode 100644 libs/lmo/src/lmo_lualib.c create mode 100644 libs/lmo/src/lmo_lualib.h create mode 100644 libs/lmo/src/lmo_po2lmo.c create mode 100644 libs/lmo/standalone.mk diff --git a/libs/lmo/Makefile b/libs/lmo/Makefile new file mode 100644 index 000000000..a15390cbe --- /dev/null +++ b/libs/lmo/Makefile @@ -0,0 +1,46 @@ +ifneq (,$(wildcard ../../build/config.mk)) +include ../../build/config.mk +include ../../build/module.mk +include ../../build/gccconfig.mk +else +include standalone.mk +endif + +LMO_LDFLAGS = +LMO_CFLAGS = +LMO_SO = lmo.so +LMO_PO2LMO = po2lmo +LMO_LOOKUP = lookup +LMO_COMMON_OBJ = src/lmo_core.o src/lmo_hash.o +LMO_PO2LMO_OBJ = src/lmo_po2lmo.o +LMO_LOOKUP_OBJ = src/lmo_lookup.o +LMO_LUALIB_OBJ = src/lmo_lualib.o + +%.o: %.c + $(COMPILE) $(LMO_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< + +compile: build-clean $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ) $(LMO_LOOKUP_OBJ) $(LMO_LUALIB_OBJ) + $(LINK) $(SHLIB_FLAGS) $(LMO_LDFLAGS) -o src/$(LMO_SO) \ + $(LMO_COMMON_OBJ) $(LMO_LUALIB_OBJ) + $(LINK) $(LMO_LDFLAGS) -o src/$(LMO_PO2LMO) $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ) + $(LINK) $(LMO_LDFLAGS) -o src/$(LMO_LOOKUP) $(LMO_COMMON_OBJ) $(LMO_LOOKUP_OBJ) + mkdir -p dist$(LUA_LIBRARYDIR) + cp src/$(LMO_SO) dist$(LUA_LIBRARYDIR)/$(LMO_SO) + +install: build + cp -pR dist$(LUA_LIBRARYDIR)/* $(LUA_LIBRARYDIR) + +clean: build-clean + +build-clean: + rm -f src/*.o src/lookup src/po2lmo src/lmo.so + +host-compile: build-clean host-clean $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ) + $(LINK) $(LMO_LDFLAGS) -o src/$(LMO_PO2LMO) $(LMO_COMMON_OBJ) $(LMO_PO2LMO_OBJ) + +host-install: host-compile + cp src/$(LMO_PO2LMO) ../../build/$(LMO_PO2LMO) + +host-clean: + rm -f ../../build/$(LMO_PO2LMO) + diff --git a/libs/lmo/src/lmo.h b/libs/lmo/src/lmo.h new file mode 100644 index 000000000..ab17e873f --- /dev/null +++ b/libs/lmo/src/lmo.h @@ -0,0 +1,72 @@ +/* + * lmo - Lua Machine Objects - General header + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LMO_H_ +#define _LMO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if (defined(__GNUC__) && defined(__i386__)) +#define sfh_get16(d) (*((const uint16_t *) (d))) +#else +#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + + +struct lmo_entry { + uint32_t key_id; + uint32_t val_id; + uint32_t offset; + uint32_t length; + struct lmo_entry *next; +} __attribute__((packed)); + +typedef struct lmo_entry lmo_entry_t; + + +struct lmo_archive { + int fd; + uint32_t length; + lmo_entry_t *index; + char *mmap; +}; + +typedef struct lmo_archive lmo_archive_t; + + +uint32_t sfh_hash(const char * data, int len); + +char _lmo_error[1024]; +const char * lmo_error(void); + +lmo_archive_t * lmo_open(const char *file); +int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len); +void lmo_close(lmo_archive_t *ar); + +#endif diff --git a/libs/lmo/src/lmo_core.c b/libs/lmo/src/lmo_core.c new file mode 100644 index 000000000..b3cb7c098 --- /dev/null +++ b/libs/lmo/src/lmo_core.c @@ -0,0 +1,231 @@ +/* + * lmo - Lua Machine Objects - Base functions + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" + +extern char _lmo_error[1024]; + +static int lmo_read32( int fd, uint32_t *val ) +{ + uint8_t buffer[5]; + + if( read(fd, buffer, 4) < 4 ) + return -1; + + buffer[4] = 0; + *val = ntohl(*((uint32_t *) buffer)); + + return 4; +} + +static char * error(const char *message, int add_errno) +{ + memset(_lmo_error, 0, sizeof(_lmo_error)); + + if( add_errno ) + snprintf(_lmo_error, sizeof(_lmo_error), + "%s: %s", message, strerror(errno)); + else + snprintf(_lmo_error, sizeof(_lmo_error), "%s", message); + + return NULL; +} + +const char * lmo_error(void) +{ + return _lmo_error; +} + +lmo_archive_t * lmo_open(const char *file) +{ + int in = -1; + uint32_t idx_offset = 0; + uint32_t i; + struct stat s; + + lmo_archive_t *ar = NULL; + lmo_entry_t *head = NULL; + lmo_entry_t *entry = NULL; + + if( stat(file, &s) == -1 ) + { + error("Can not stat file", 1); + goto cleanup; + } + + if( (in = open(file, O_RDONLY)) == -1 ) + { + error("Can not open file", 1); + goto cleanup; + } + + if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 ) + { + error("Can not seek to eof", 1); + goto cleanup; + } + + if( lmo_read32(in, &idx_offset) != 4 ) + { + error("Unexpected EOF while reading index offset", 0); + goto cleanup; + } + + if( lseek(in, idx_offset, SEEK_SET) == -1 ) + { + error("Can not seek to index offset", 1); + goto cleanup; + } + + if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL ) + { + ar->fd = in; + ar->length = idx_offset; + + for( i = idx_offset; + i < (s.st_size - sizeof(uint32_t)); + i += (4 * sizeof(uint32_t)) + ) { + if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL ) + { + if( (lmo_read32(ar->fd, &entry->key_id) == 4) && + (lmo_read32(ar->fd, &entry->val_id) == 4) && + (lmo_read32(ar->fd, &entry->offset) == 4) && + (lmo_read32(ar->fd, &entry->length) == 4) + ) { + entry->next = head; + head = entry; + } + else + { + error("Unexpected EOF while reading index entry", 0); + goto cleanup; + } + } + else + { + error("Out of memory", 0); + goto cleanup; + } + } + + ar->index = head; + + if( lseek(ar->fd, 0, SEEK_SET) == -1 ) + { + error("Can not seek to start", 1); + goto cleanup; + } + + if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED ) + { + error("Failed to memory map archive contents", 1); + goto cleanup; + } + + return ar; + } + else + { + error("Out of memory", 0); + goto cleanup; + } + + + cleanup: + + if( in > -1 ) + close(in); + + if( head != NULL ) + { + entry = head; + + while( entry != NULL ) + { + head = entry->next; + free(entry); + entry = head; + } + + head = entry = NULL; + } + + if( ar != NULL ) + { + if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) + munmap(ar->mmap, ar->length); + + free(ar); + ar = NULL; + } + + return NULL; +} + +void lmo_close(lmo_archive_t *ar) +{ + lmo_entry_t *head = NULL; + lmo_entry_t *entry = NULL; + + if( ar != NULL ) + { + entry = ar->index; + + while( entry != NULL ) + { + head = entry->next; + free(entry); + entry = head; + } + + head = entry = NULL; + + if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) + munmap(ar->mmap, ar->length); + + close(ar->fd); + free(ar); + + ar = NULL; + } +} + +int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len) +{ + uint32_t look_key = sfh_hash(key, strlen(key)); + int copy_len = -1; + + lmo_entry_t *entry = ar->index; + + while( entry != NULL ) + { + if( entry->key_id == look_key ) + { + copy_len = (len > entry->length) ? entry->length : len; + memcpy(dest, &ar->mmap[entry->offset], copy_len); + + break; + } + + entry = entry->next; + } + + return copy_len; +} + diff --git a/libs/lmo/src/lmo_hash.c b/libs/lmo/src/lmo_hash.c new file mode 100644 index 000000000..bc8e6fe4e --- /dev/null +++ b/libs/lmo/src/lmo_hash.c @@ -0,0 +1,53 @@ +/* + * Hash function from http://www.azillionmonkeys.com/qed/hash.html + * Copyright (C) 2004-2008 by Paul Hsieh + */ + +#include "lmo.h" + +uint32_t sfh_hash(const char * data, int len) +{ + uint32_t hash = len, tmp; + int rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) { + hash += sfh_get16(data); + tmp = (sfh_get16(data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof(uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += sfh_get16(data); + hash ^= hash << 16; + hash ^= data[sizeof(uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += sfh_get16(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + diff --git a/libs/lmo/src/lmo_lookup.c b/libs/lmo/src/lmo_lookup.c new file mode 100644 index 000000000..8b48f7fac --- /dev/null +++ b/libs/lmo/src/lmo_lookup.c @@ -0,0 +1,58 @@ +/* + * lmo - Lua Machine Objects - Lookup utility + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" + +extern char _lmo_error[1024]; + +static void die(const char *msg) +{ + printf("Error: %s\n", msg); + exit(1); +} + +static void usage(const char *name) +{ + printf("Usage: %s input.lmo key\n", name); + exit(1); +} + +int main(int argc, char *argv[]) +{ + char val[4096]; + lmo_archive_t *ar = NULL; + + if( argc != 3 ) + usage(argv[0]); + + if( (ar = (lmo_archive_t *) lmo_open(argv[1])) != NULL ) + { + if( lmo_lookup(ar, argv[2], val, sizeof(val)) > -1 ) + { + printf("%s\n", val); + } + + lmo_close(ar); + } + else + { + die(lmo_error()); + } + + return 0; +} diff --git a/libs/lmo/src/lmo_lualib.c b/libs/lmo/src/lmo_lualib.c new file mode 100644 index 000000000..3f9170e88 --- /dev/null +++ b/libs/lmo/src/lmo_lualib.c @@ -0,0 +1,124 @@ +/* + * lmo - Lua Machine Objects - Lookup utility + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo_lualib.h" + +extern char _lmo_error[1024]; + + +static int lmo_L_open(lua_State *L) { + const char *filename = luaL_checklstring(L, 1, NULL); + lmo_archive_t *ar, **udata; + + if( (ar = lmo_open(filename)) != NULL ) + { + if( (udata = lua_newuserdata(L, sizeof(lmo_archive_t *))) != NULL ) + { + *udata = ar; + luaL_getmetatable(L, LMO_ARCHIVE_META); + lua_setmetatable(L, -2); + return 1; + } + + lua_pushnil(L); + lua_pushstring(L, "out of memory"); + return 2; + } + + lua_pushnil(L); + lua_pushstring(L, lmo_error()); + return 2; +} + +static int lmo_L_hash(lua_State *L) { + const char *data = luaL_checkstring(L, 1); + uint32_t hash = sfh_hash(data, strlen(data)); + lua_pushnumber(L, hash); + return 1; +} + +static int lmo_L_lookup(lua_State *L) { + lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); + lmo_entry_t *e = (*ar)->index; + const char *key = luaL_checkstring(L, 2); + uint32_t hash = sfh_hash(key, strlen(key)); + + while( e != NULL ) + { + if( e->key_id == hash ) + { + lua_pushlstring(L, &(*ar)->mmap[e->offset], e->length); + return 1; + } + + e = e->next; + } + + lua_pushnil(L); + return 1; +} + +static int lmo_L__gc(lua_State *L) { + lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); + + if( (*ar) != NULL ) + lmo_close(*ar); + + *ar = NULL; + + return 0; +} + +static int lmo_L__tostring(lua_State *L) { + lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META); + lua_pushfstring(L, "LMO Archive (%d bytes)", (*ar)->length); + return 1; +} + + +/* method table */ +static const luaL_reg M[] = { + {"close", lmo_L__gc}, + {"lookup", lmo_L_lookup}, + {"__tostring", lmo_L__tostring}, + {"__gc", lmo_L__gc}, + {NULL, NULL} +}; + +/* module table */ +static const luaL_reg R[] = { + {"open", lmo_L_open}, + {"hash", lmo_L_hash}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_lmo(lua_State *L) { + luaL_newmetatable(L, LMO_LUALIB_META); + luaL_register(L, NULL, R); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_setglobal(L, LMO_LUALIB_META); + + luaL_newmetatable(L, LMO_ARCHIVE_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_setglobal(L, LMO_ARCHIVE_META); + + return 1; +} diff --git a/libs/lmo/src/lmo_lualib.h b/libs/lmo/src/lmo_lualib.h new file mode 100644 index 000000000..096fa027f --- /dev/null +++ b/libs/lmo/src/lmo_lualib.h @@ -0,0 +1,33 @@ +/* + * lmo - Lua Machine Objects - Lua library header + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LMO_LUALIB_H_ +#define _LMO_LUALIB_H_ + +#include +#include +#include + +#include "lmo.h" + +#define LMO_LUALIB_META "lmo" +#define LMO_ARCHIVE_META "lmo.archive" + +LUALIB_API int luaopen_lmo(lua_State *L); + +#endif diff --git a/libs/lmo/src/lmo_po2lmo.c b/libs/lmo/src/lmo_po2lmo.c new file mode 100644 index 000000000..9f78ff2ad --- /dev/null +++ b/libs/lmo/src/lmo_po2lmo.c @@ -0,0 +1,199 @@ +/* + * lmo - Lua Machine Objects - PO to LMO conversion tool + * + * Copyright (C) 2009 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" + +static void die(const char *msg) +{ + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s input.po output.lmo\n", name); + exit(1); +} + +static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + if( fwrite(ptr, size, nmemb, stream) == 0 ) + die("Failed to write stdout"); +} + +static int extract_string(const char *src, char *dest, int len) +{ + int pos = 0; + int esc = 0; + int off = -1; + + for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ ) + { + if( (off == -1) && (src[pos] == '"') ) + { + off = pos + 1; + } + else if( off >= 0 ) + { + if( esc == 1 ) + { + dest[pos-off] = src[pos]; + esc = 0; + } + else if( src[pos] == '\\' ) + { + off++; + esc = 1; + + } + else if( src[pos] != '"' ) + { + dest[pos-off] = src[pos]; + } + else + { + dest[pos-off] = '\0'; + break; + } + } + } + + return (off > -1) ? strlen(dest) : -1; +} + +int main(int argc, char *argv[]) +{ + char line[4096]; + char key[4096]; + char val[4096]; + char tmp[4096]; + int state = 0; + int offset = 0; + int length = 0; + + FILE *in; + FILE *out; + + lmo_entry_t *head = NULL; + lmo_entry_t *entry = NULL; + + if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) + usage(argv[0]); + + memset(line, 0, sizeof(key)); + memset(key, 0, sizeof(val)); + memset(val, 0, sizeof(val)); + + while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) + { + if( state == 0 && strstr(line, "msgid \"") == line ) + { + switch(extract_string(line, key, sizeof(key))) + { + case -1: + die("Syntax error in msgid"); + case 0: + continue; + default: + state = 1; + } + } + else if( state == 1 && strstr(line, "msgstr \"") == line ) + { + switch(extract_string(line, val, sizeof(val))) + { + case -1: + die("Syntax error in msgstr"); + case 0: + state = 2; + break; + default: + state = 3; + } + } + else if( state == 2 ) + { + switch(extract_string(line, tmp, sizeof(tmp))) + { + case -1: + state = 3; + break; + default: + strcat(val, tmp); + } + } + else if( state == 3 ) + { + if( strlen(key) > 0 && strlen(val) > 0 ) + { + if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL ) + { + memset(entry, 0, sizeof(entry)); + length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); + + entry->key_id = htonl(sfh_hash(key, strlen(key))); + entry->val_id = htonl(sfh_hash(val, strlen(val))); + entry->offset = htonl(offset); + entry->length = htonl(strlen(val)); + + print(val, length, 1, out); + offset += length; + + entry->next = head; + head = entry; + } + else + { + die("Out of memory"); + } + } + + state = 0; + memset(key, 0, sizeof(key)); + memset(val, 0, sizeof(val)); + } + + memset(line, 0, sizeof(line)); + } + + entry = head; + while( entry != NULL ) + { + print(&entry->key_id, sizeof(uint32_t), 1, out); + print(&entry->val_id, sizeof(uint32_t), 1, out); + print(&entry->offset, sizeof(uint32_t), 1, out); + print(&entry->length, sizeof(uint32_t), 1, out); + entry = entry->next; + } + + if( offset > 0 ) + { + offset = htonl(offset); + print(&offset, sizeof(uint32_t), 1, out); + fsync(fileno(out)); + fclose(out); + } + else + { + fclose(out); + unlink(argv[2]); + } + + fclose(in); + return(0); +} diff --git a/libs/lmo/standalone.mk b/libs/lmo/standalone.mk new file mode 100644 index 000000000..66a0e5a2e --- /dev/null +++ b/libs/lmo/standalone.mk @@ -0,0 +1,56 @@ +LUAC = luac +LUAC_OPTIONS = -s +LUA_TARGET ?= source + +LUA_MODULEDIR = /usr/local/share/lua/5.1 +LUA_LIBRARYDIR = /usr/local/lib/lua/5.1 + +OS ?= $(shell uname) + +LUA_SHLIBS = $(shell pkg-config --silence-errors --libs lua5.1 || pkg-config --silence-errors --libs lua-5.1 || pkg-config --silence-errors --libs lua) +LUA_LIBS = $(if $(LUA_SHLIBS),$(LUA_SHLIBS),$(firstword $(wildcard /usr/lib/liblua.a /usr/local/lib/liblua.a /opt/local/lib/liblua.a))) +LUA_CFLAGS = $(shell pkg-config --silence-errors --cflags lua5.1 || pkg-config --silence-errors --cflags lua-5.1 || pkg-config --silence-errors --cflags lua) + +CC = gcc +AR = ar +RANLIB = ranlib +CFLAGS = -O2 +FPIC = -fPIC +EXTRA_CFLAGS = --std=gnu99 +WFLAGS = -Wall -Werror -pedantic +CPPFLAGS = +COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $(WFLAGS) +ifeq ($(OS),Darwin) + SHLIB_FLAGS = -bundle -undefined dynamic_lookup +else + SHLIB_FLAGS = -shared +endif +LINK = $(CC) $(LDFLAGS) + +.PHONY: all build compile luacompile luasource clean luaclean + +all: build + +build: luabuild gccbuild + +luabuild: lua$(LUA_TARGET) + +gccbuild: compile +compile: + +clean: luaclean + +luasource: + mkdir -p dist$(LUA_MODULEDIR) + cp -pR root/* dist 2>/dev/null || true + cp -pR lua/* dist$(LUA_MODULEDIR) 2>/dev/null || true + for i in $$(find dist -name .svn); do rm -rf $$i || true; done + +luastrip: luasource + for i in $$(find dist -type f -name '*.lua'); do perl -e 'undef $$/; open( F, "< $$ARGV[0]" ) || die $$!; $$src = ; close F; $$src =~ s/--\[\[.*?\]\](--)?//gs; $$src =~ s/^\s*--.*?\n//gm; open( F, "> $$ARGV[0]" ) || die $$!; print F $$src; close F' $$i; done + +luacompile: luasource + for i in $$(find dist -name *.lua -not -name debug.lua); do $(LUAC) $(LUAC_OPTIONS) -o $$i $$i; done + +luaclean: + rm -rf dist -- 2.11.0