diff --git a/.gitattributes b/.gitattributes index 9e831d1f4b5..601eee91ba9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,7 @@ docs/windows.txt svneol=native#text/plain /makefile svneol=native#text/plain src/build/build.mak svneol=native#text/plain src/build/file2str.c svneol=native#text/plain +src/build/makedep.c svneol=native#text/plain src/build/png2bdc.c svneol=native#text/plain src/build/verinfo.c svneol=native#text/plain src/emu/addrmap.c svneol=native#text/plain diff --git a/makefile b/makefile index 08b5823fd74..dbcd332cf42 100644 --- a/makefile +++ b/makefile @@ -489,7 +489,7 @@ COBJFLAGS += \ #------------------------------------------------- # add core include paths -CCOMFLAGS += \ +INCPATH += \ -I$(SRC)/$(TARGET) \ -I$(OBJ)/$(TARGET)/layout \ -I$(SRC)/emu \ @@ -500,6 +500,7 @@ CCOMFLAGS += \ -I$(SRC)/osd/$(OSD) \ + #------------------------------------------------- # archiving flags #------------------------------------------------- @@ -585,7 +586,7 @@ LIBS = # add expat XML library ifeq ($(BUILD_EXPAT),1) -CCOMFLAGS += -I$(SRC)/lib/expat +INCPATH += -I$(SRC)/lib/expat EXPAT = $(OBJ)/libexpat.a else LIBS += -lexpat @@ -594,7 +595,7 @@ endif # add ZLIB compression library ifeq ($(BUILD_ZLIB),1) -CCOMFLAGS += -I$(SRC)/lib/zlib +INCPATH += -I$(SRC)/lib/zlib ZLIB = $(OBJ)/libz.a else LIBS += -lz @@ -643,6 +644,7 @@ include $(SRC)/build/build.mak include $(SRC)/tools/tools.mak # combine the various definitions to one +CCOMFLAGS += $(INCPATH) CDEFS = $(DEFS) @@ -655,6 +657,22 @@ emulator: maketree $(BUILD) $(EMULATOR) buildtools: maketree $(BUILD) +# In order to keep dependencies reasonable, we exclude objects in the base of +# $(SRC)/emu, as well as all the OSD objects and anything in the $(OBJ) tree +depend: maketree $(MAKEDEP_TARGET) + @echo Rebuilding depend.mak... + $(MAKEDEP) -I. $(INCPATH) -X$(SRC)/emu -X$(SRC)/osd/... -X$(OBJ)/... src/mame > depend.mak + +INCPATH += \ + -I$(SRC)/$(TARGET) \ + -I$(OBJ)/$(TARGET)/layout \ + -I$(SRC)/emu \ + -I$(OBJ)/emu \ + -I$(OBJ)/emu/layout \ + -I$(SRC)/lib/util \ + -I$(SRC)/osd \ + -I$(SRC)/osd/$(OSD) \ + tools: maketree $(TOOLS) maketree: $(sort $(OBJDIRS)) @@ -725,11 +743,11 @@ $(OBJ)/%.s: $(SRC)/%.c | $(OSPREBUILD) @echo Compiling $<... $(CC) $(CDEFS) $(CFLAGS) -S $< -o $@ -$(OBJ)/%.lh: $(SRC)/%.lay $(FILE2STR) +$(OBJ)/%.lh: $(SRC)/%.lay $(FILE2STR_TARGET) @echo Converting $<... @$(FILE2STR) $< $@ layout_$(basename $(notdir $<)) -$(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC) $(FILE2STR) +$(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC_TARGET) $(FILE2STR_TARGET) @echo Converting $<... @$(PNG2BDC) $< $(OBJ)/temp.bdc @$(FILE2STR) $(OBJ)/temp.bdc $@ font_$(basename $(notdir $<)) UINT8 @@ -745,3 +763,10 @@ $(OBJ)/%.o: $(SRC)/%.m | $(OSPREBUILD) $(CC) $(CDEFS) $(COBJFLAGS) $(CCOMFLAGS) -c $< -o $@ endif + + +#------------------------------------------------- +# optional dependencies file +#------------------------------------------------- + +-include depend.mak diff --git a/src/build/build.mak b/src/build/build.mak index 38e79b7434d..721346a3f6c 100644 --- a/src/build/build.mak +++ b/src/build/build.mak @@ -18,15 +18,29 @@ OBJDIRS += \ # set of build targets #------------------------------------------------- -FILE2STR = $(BUILDOUT)/file2str$(BUILD_EXE) -PNG2BDC = $(BUILDOUT)/png2bdc$(BUILD_EXE) -VERINFO = $(BUILDOUT)/verinfo$(BUILD_EXE) +FILE2STR_TARGET = $(BUILDOUT)/file2str$(BUILD_EXE) +MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE) +PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE) +VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE) + +ifeq ($(TARGETOS),win32) +FILE2STR = $(subst /,\,$(FILE2STR_TARGET)) +MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET)) +PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET)) +VERINFO = $(subst /,\,$(VERINFO_TARGET)) +else +FILE2STR = $(FILE2STR_TARGET) +MAKEDEP = $(MAKEDEP_TARGET) +PNG2BDC = $(PNG2BDC_TARGET) +VERINFO = $(VERINFO_TARGET) +endif ifneq ($(CROSS_BUILD),1) BUILD += \ - $(FILE2STR) \ - $(PNG2BDC) \ - $(VERINFO) \ + $(FILE2STR_TARGET) \ + $(MAKEDEP_TARGET) \ + $(PNG2BDC_TARGET) \ + $(VERINFO_TARGET) \ @@ -37,7 +51,20 @@ BUILD += \ FILE2STROBJS = \ $(BUILDOBJ)/file2str.o \ -$(FILE2STR): $(FILE2STROBJS) $(LIBOCORE) +$(FILE2STR_TARGET): $(FILE2STROBJS) $(LIBOCORE) + @echo Linking $@... + $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ + + + +#------------------------------------------------- +# makedep +#------------------------------------------------- + +MAKEDEPOBJS = \ + $(BUILDOBJ)/makedep.o \ + +$(MAKEDEP_TARGET): $(MAKEDEPOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) @echo Linking $@... $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ @@ -50,7 +77,7 @@ $(FILE2STR): $(FILE2STROBJS) $(LIBOCORE) PNG2BDCOBJS = \ $(BUILDOBJ)/png2bdc.o \ -$(PNG2BDC): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) +$(PNG2BDC_TARGET): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) @echo Linking $@... $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ @@ -63,7 +90,7 @@ $(PNG2BDC): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB) VERINFOOBJS = \ $(BUILDOBJ)/verinfo.o -$(VERINFO): $(VERINFOOBJS) $(LIBOCORE) +$(VERINFO_TARGET): $(VERINFOOBJS) $(LIBOCORE) @echo Linking $@... $(LD) $(LDFLAGS) $^ $(LIBS) -o $@ diff --git a/src/build/makedep.c b/src/build/makedep.c new file mode 100644 index 00000000000..da7284c2618 --- /dev/null +++ b/src/build/makedep.c @@ -0,0 +1,542 @@ +/*************************************************************************** + + MAME source code dependency generator + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#include +#include +#include +#include +#include +#include "osdcore.h" +#include "astring.h" +#include "corefile.h" +#include "tagmap.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define HASH_SIZE 193 + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _include_path include_path; +struct _include_path +{ + include_path * next; + const astring * path; +}; + + +typedef struct _exclude_path exclude_path; +struct _exclude_path +{ + exclude_path * next; + const astring * path; + int pathlen; + UINT8 recursive; +}; + + +typedef struct _list_entry list_entry; +struct _list_entry +{ + list_entry * next; + const astring * name; +}; + + +typedef struct _file_entry file_entry; + +typedef struct _dependency dependency; +struct _dependency +{ + dependency * next; + file_entry * file; +}; + + +struct _file_entry +{ + astring * name; + dependency * deplist; +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static include_path *incpaths; +static exclude_path *excpaths; +static tagmap *file_map; + + + +/*************************************************************************** + PROTOTYPES +***************************************************************************/ + +/* core output functions */ +static int recurse_dir(int srcrootlen, const astring *srcdir); +static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile); + +/* path helpers */ +static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/* core output functions */ +static int recurse_dir(int srcrootlen, const astring *srcdir); +static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile); + +/* path helpers */ +static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename); + + + +/*************************************************************************** + MAIN +***************************************************************************/ + +/*------------------------------------------------- + main - main entry point +-------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + include_path **incpathhead = &incpaths; + exclude_path **excpathhead = &excpaths; + astring *srcdir = NULL; + int unadorned = 0; + int result; + int argnum; + + /* loop over arguments */ + for (argnum = 1; argnum < argc; argnum++) + { + char *arg = argv[argnum]; + + /* include path? */ + if (arg[0] == '-' && arg[1] == 'I') + { + *incpathhead = (include_path *)malloc(sizeof(**incpathhead)); + if (*incpathhead != NULL) + { + (*incpathhead)->next = NULL; + (*incpathhead)->path = astring_replacechr(astring_dupc(&arg[2]), '/', PATH_SEPARATOR[0]); + incpathhead = &(*incpathhead)->next; + } + } + + /* exclude path? */ + else if (arg[0] == '-' && arg[1] == 'X') + { + *excpathhead = (exclude_path *)malloc(sizeof(**excpathhead)); + if (*excpathhead != NULL) + { + astring *path; + (*excpathhead)->next = NULL; + path = astring_replacechr(astring_dupc(&arg[2]), PATH_SEPARATOR[0], '/'); + (*excpathhead)->recursive = (astring_replacec(path, astring_len(path) - 4, "/...", "") != 0); + (*excpathhead)->path = path; + (*excpathhead)->pathlen = astring_len(path); + excpathhead = &(*excpathhead)->next; + } + } + + /* other parameter */ + else if (arg[0] != '-' && unadorned == 0) + { + srcdir = astring_replacechr(astring_dupc(arg), '/', PATH_SEPARATOR[0]); + unadorned++; + } + else + goto usage; + } + + /* make sure we got 1 parameter */ + if (srcdir == NULL) + goto usage; + + /* create a tagmap for tracking files we've visited */ + file_map = tagmap_alloc(); + + /* recurse over subdirectories */ + result = recurse_dir(astring_len(srcdir), srcdir); + + /* free source and destination directories */ + tagmap_free(file_map); + astring_free(srcdir); + return result; + +usage: + fprintf(stderr, "Usage:\n%s [-Iincpath [-Iincpath [...]]]\n", argv[0]); + return 1; +} + + + +/*************************************************************************** + CORE OUTPUT FUNCTIONS +***************************************************************************/ + +static int compare_list_entries(const void *p1, const void *p2) +{ + const list_entry *entry1 = *(const list_entry **)p1; + const list_entry *entry2 = *(const list_entry **)p2; + return strcmp(astring_c(entry1->name), astring_c(entry2->name)); +} + + +/*------------------------------------------------- + recurse_dependencies - recurse through the + dependencies found, adding the mto the tagmap + unless we already exist in the map +-------------------------------------------------*/ + +static void recurse_dependencies(file_entry *file, tagmap *map) +{ + int filelen = astring_len(file->name); + exclude_path *exclude; + dependency *dep; + + /* skip if we're in an exclude path */ + for (exclude = excpaths; exclude != NULL; exclude = exclude->next) + if (exclude->pathlen < filelen && strncmp(astring_c(file->name), astring_c(exclude->path), exclude->pathlen) == 0) + if (exclude->recursive || astring_chr(file->name, exclude->pathlen + 1, '/') == -1) + return; + + /* attempt to add; if we get an error, we're already present */ + if (tagmap_add(map, astring_c(file->name), file->name, FALSE) != TMERR_NONE) + return; + + /* recurse the list from there */ + for (dep = file->deplist; dep != NULL; dep = dep->next) + recurse_dependencies(dep->file, map); +} + + +/*------------------------------------------------- + recurse_dir - recurse through a directory +-------------------------------------------------*/ + +static int recurse_dir(int srcrootlen, const astring *srcdir) +{ + static const osd_dir_entry_type typelist[] = { ENTTYPE_DIR, ENTTYPE_FILE }; + int result = 0; + int entindex; + + /* iterate first over directories, then over files */ + for (entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++) + { + osd_dir_entry_type entry_type = typelist[entindex]; + const osd_directory_entry *entry; + list_entry **listarray = NULL; + list_entry *list = NULL; + list_entry *curlist; + osd_directory *dir; + int found = 0; + + /* open the directory and iterate through it */ + dir = osd_opendir(astring_c(srcdir)); + if (dir == NULL) + { + result = 1; + goto error; + } + + /* build up the list of files */ + while ((entry = osd_readdir(dir)) != NULL) + if (entry->type == entry_type && entry->name[0] != '.') + { + list_entry *lentry = (list_entry *)malloc(sizeof(*lentry)); + lentry->name = astring_dupc(entry->name); + lentry->next = list; + list = lentry; + found++; + } + + /* close the directory */ + osd_closedir(dir); + + /* skip if nothing found */ + if (found == 0) + continue; + + /* allocate memory for sorting */ + listarray = (list_entry **)malloc(sizeof(list_entry *) * found); + found = 0; + for (curlist = list; curlist != NULL; curlist = curlist->next) + listarray[found++] = curlist; + + /* sort the list */ + qsort(listarray, found, sizeof(listarray[0]), compare_list_entries); + + /* rebuild the list */ + list = NULL; + while (--found >= 0) + { + listarray[found]->next = list; + list = listarray[found]; + } + free(listarray); + + /* iterate through each file */ + for (curlist = list; curlist != NULL && result == 0; curlist = curlist->next) + { + astring *srcfile; + + /* build the source filename */ + srcfile = astring_alloc(); + astring_printf(srcfile, "%s%c%s", astring_c(srcdir), PATH_SEPARATOR[0], astring_c(curlist->name)); + + /* if we have a file, output it */ + if (entry_type == ENTTYPE_FILE) + { + /* make sure we care, first */ + if (core_filename_ends_with(astring_c(curlist->name), ".c")) + { + tagmap *depend_map = tagmap_alloc(); + tagmap_entry *entry; + file_entry *file; + astring *target; + int taghash; + + /* find dependencies */ + file = compute_dependencies(srcrootlen, srcfile); + recurse_dependencies(file, depend_map); + + /* convert the target from source to object (makes assumptions about rules) */ + target = astring_dup(file->name); + astring_replacec(target, 0, "src/", "$(OBJ)/"); + astring_replacec(target, 0, ".c", ".o"); + printf("\n%s : \\\n", astring_c(target)); + + /* iterate over the hashed dependencies and output them as well */ + for (taghash = 0; taghash < TAGMAP_HASH_SIZE; taghash++) + for (entry = depend_map->table[taghash]; entry != NULL; entry = entry->next) + printf("\t%s \\\n", astring_c((astring *)entry->object)); + + astring_free(target); + tagmap_free(depend_map); + } + } + + /* if we have a directory, recurse */ + else + result = recurse_dir(srcrootlen, srcfile); + + /* free memory for the names */ + astring_free(srcfile); + } + + /* free all the allocated entries */ + while (list != NULL) + { + list_entry *next = list->next; + astring_free((astring *)list->name); + free(list); + list = next; + } + } + +error: + return result; +} + + +/*------------------------------------------------- + output_file - output a file, converting to + HTML +-------------------------------------------------*/ + +static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile) +{ + astring *normalfile; + UINT32 filelength; + file_entry *file; + char *filedata; + int found = 0; + int index; + + /* see if we already have an entry */ + normalfile = astring_dup(srcfile); + astring_replacechr(normalfile, PATH_SEPARATOR[0], '/'); + file = (file_entry *)tagmap_find(file_map, astring_c(normalfile)); + if (file != NULL) + return file; + + /* create a new header entry */ + file = (file_entry *)malloc(sizeof(*file)); + file->deplist = NULL; + file->name = normalfile; + tagmap_add(file_map, astring_c(file->name), file, FALSE); + + /* read the source file */ + if (core_fload(astring_c(srcfile), (void **)&filedata, &filelength) != FILERR_NONE) + { + fprintf(stderr, "Unable to read file '%s'\n", astring_c(srcfile)); + return file; + } + + /* find the #include directives in this file */ + for (index = 0; index < filelength; index++) + if (filedata[index] == '#' && strncmp(&filedata[index + 1], "include", 7) == 0) + { + astring *filename, *target; + int scan = index; + dependency *dep; + int start; + + /* first make sure we're not commented or quoted */ + for (scan = index; scan > 2 && filedata[scan] != 13 && filedata[scan] != 10; scan--) + if ((filedata[scan] == '/' && filedata[scan - 1] == '/') || filedata[scan] == '"') + break; + if (filedata[scan] != 13 && filedata[scan] != 10) + continue; + + /* scan forward to find the quotes or bracket */ + index += 7; + for (scan = index; scan < filelength && filedata[scan] != '<' && filedata[scan] != '"' && filedata[scan] != 13 && filedata[scan] != 10; scan++) ; + + /* ignore if not found or if it's bracketed */ + if (scan >= filelength || filedata[scan] != '"') + continue; + start = ++scan; + + /* find the closing quote */ + while (scan < filelength && filedata[scan] != '"') + scan++; + if (scan >= filelength) + continue; + + /* find the include file */ + filename = astring_dupch(&filedata[start], scan - start); + target = find_include_file(srcrootlen, srcfile, filename); + + /* create a new dependency */ + if (target != NULL) + { + dep = (dependency *)malloc(sizeof(*dep)); + dep->next = file->deplist; + file->deplist = dep; + dep->file = compute_dependencies(srcrootlen, target); + astring_free(target); + } + + astring_free(filename); + } + + free(filedata); + return file; +} + + + +/*************************************************************************** + HELPERS +***************************************************************************/ + +/*------------------------------------------------- + find_include_file - find an include file +-------------------------------------------------*/ + +static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename) +{ + include_path *curpath; + + /* iterate over include paths and find the file */ + for (curpath = incpaths; curpath != NULL; curpath = curpath->next) + { + astring *srcincpath = astring_dup(curpath->path); + core_file *testfile; + int lastsepindex = 0; + int sepindex; + + /* a '.' include path is specially treated */ + if (astring_cmpc(curpath->path, ".") == 0) + astring_cpysubstr(srcincpath, srcfile, 0, astring_rchr(srcfile, 0, PATH_SEPARATOR[0])); + + /* append the filename piecemeal to account for directories */ + while ((sepindex = astring_chr(filename, lastsepindex, '/')) != -1) + { + astring *pathpart = astring_dupsubstr(filename, lastsepindex, sepindex - lastsepindex); + + /* handle .. by removing a chunk from the incpath */ + if (astring_cmpc(pathpart, "..") == 0) + { + int sepindex = astring_rchr(srcincpath, 0, PATH_SEPARATOR[0]); + if (sepindex != -1) + astring_substr(srcincpath, 0, sepindex); + } + + /* otherwise, append a path separator and the pathpart */ + else + astring_cat(astring_catc(srcincpath, PATH_SEPARATOR), pathpart); + + /* advance past the previous index */ + lastsepindex = sepindex + 1; + + /* free the path part we extracted */ + astring_free(pathpart); + } + + /* now append the filename */ + astring_catsubstr(astring_catc(srcincpath, PATH_SEPARATOR), filename, lastsepindex, -1); + + /* see if we can open it */ + if (core_fopen(astring_c(srcincpath), OPEN_FLAG_READ, &testfile) == FILERR_NONE) + { + /* close the file */ + core_fclose(testfile); + return srcincpath; + } + + /* free our include path */ + astring_free(srcincpath); + } + return NULL; +}