summaryrefslogblamecommitdiffstatshomepage
path: root/src/build/makedep.c
blob: 85d024e6dbf511ba7e0b08c77a611eb51c1aa24b (plain) (tree)
1
2
3
4
5
6

                                



                                                                            
















                                                                            
                           





                                                                            
                   
 

                             


  
                   
 



                                  


  
                 
 

                             


  
                  
 
                 
 

                             


  
                 
 

                                

  

                                       







                                                                            
                                       






                                                                            


                                                                          
 

                                                                                                                    










                                                                            





                                                                                       



                                               
                       
                          
 

                                                     


                                         
                                

                                                   



                                                                                             

                 
                                

                                                        





                                                                                                                                    
                 
 



                                                        
 




                                                                                                     
 
                                                                                                            




                                                     
                                  

                                                         
                                                                           


                                    
                                       

         


                                       
 

                                                 











                                                                            
                                              








                                                   
                                                                       
 




                                                                                                           
                                       
 
                                                                    
                                                
                       
 


                                                                          






                                                   
                                                       


                                                                                   
 

                                                                                            

                                                                   
 

                                                            





                                   



                                                 


                                                                               

                                                                    




                                                    
                                      

                                  
                                        


                                 

                                                                 
                          
                                                                                          

                                                     
                                

                                                                                    
                                   





                                                      
                                   
 

                                                                                                         
                 
                                        
 

                                                                                                         
 
                                                       

                                                       

                                                                                 
                                 
                                                                  
 


                                                                                                     
 




                                                                                                                   
 
                                                                                                       

                                                                                                                                                


                                 
                                                          

                                                                          

                 
                                                 


                                                      
                                    













                                                   
                                                                         
 













                                                          
                          
                       
                                                                                
         
                                                                              


                            

                                                        

                                                                                               


                                                                                                                
                                                                                                                  
                                 
                                                             
                                              

                                          
                                         
 
                                                                     
                                   
                                 
                                                                                                                                                                         
 
                                                                   

                                                                        
                                           
 
                                                 




                                                                          


                                                                         
 

                                                                                     
                         



                                                                                      
                         

                 
                           












                                                                            
                                                                                                                   
 

                                                                                        
         






                                                                                             

                                     
                                                                          
                 
                                                                                          
 

                                                                         
                         
                                                                                          
                                                        
                                                                            

                         
                                                                              
                            
                                                                             
 
                                                          
                                                    

                 

                                                                                     
 


                                                                                     
                 
                                         
                                              
                                    
                 
         
                     
 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    MAME source code dependency generator

***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <zlib.h>
#include "osdcore.h"
#include "astring.h"
#include "corefile.h"
#include "tagmap.h"


/***************************************************************************
    CONSTANTS
***************************************************************************/

#define HASH_SIZE       193


/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

struct include_path
{
	include_path *  next;
	astring         path;
};


struct exclude_path
{
	exclude_path *  next;
	astring         path;
	int             pathlen;
	UINT8           recursive;
};


struct list_entry
{
	list_entry *    next;
	astring         name;
};


struct file_entry;

struct dependency
{
	dependency *    next;
	file_entry *    file;
};


struct file_entry
{
	astring         name;
	dependency *    deplist;
};

typedef tagmap_t<UINT8> dependency_map;



/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

static include_path *incpaths;
static exclude_path *excpaths;
static tagmap_t<file_entry *> file_map;



/***************************************************************************
    PROTOTYPES
***************************************************************************/

// core output functions
static int recurse_dir(int srcrootlen, astring &srcdir);
static file_entry &compute_dependencies(int srcrootlen, astring &srcfile);

// path helpers
static bool find_include_file(astring &srcincpath, int srcrootlen, const astring &srcfile, const astring &filename);



/***************************************************************************
    MAIN
***************************************************************************/

/*-------------------------------------------------
    main - main entry point
-------------------------------------------------*/

void usage(const char *argv0)
{
	fprintf(stderr, "Usage:\n%s <srcroot> [-Iincpath [-Iincpath [...]]]\n", argv0);
	exit(1);
}

int main(int argc, char *argv[])
{
	include_path **incpathhead = &incpaths;
	exclude_path **excpathhead = &excpaths;
	astring srcdir;
	int unadorned = 0;

	// loop over arguments
	for (int argnum = 1; argnum < argc; argnum++)
	{
		char *arg = argv[argnum];

		// include path?
		if (arg[0] == '-' && arg[1] == 'I')
		{
			*incpathhead = new include_path;
			(*incpathhead)->next = NULL;
			(*incpathhead)->path.cpy(&arg[2]).replacechr('/', PATH_SEPARATOR[0]);
			incpathhead = &(*incpathhead)->next;
		}

		// exclude path?
		else if (arg[0] == '-' && arg[1] == 'X')
		{
			*excpathhead = new exclude_path;
			(*excpathhead)->next = NULL;
			(*excpathhead)->path.cpy(&arg[2]).replacechr(PATH_SEPARATOR[0], '/');
			(*excpathhead)->recursive = ((*excpathhead)->path.replace((*excpathhead)->path.len() - 4, "/...", "") != 0);
			(*excpathhead)->pathlen = (*excpathhead)->path.len();
			excpathhead = &(*excpathhead)->next;
		}

		else if (arg[0] == '-' && arg[1] == 'F')
		{
			argnum++;
		}

		else if (arg[0] == '-' && arg[1] == 'D')
		{
			// some pkgconfigs return defines (e.g. pkg-config QtGui --cflags) ==> ignore
			argnum++;
		}

		// ignore -include which is used by sdlmame to include sdlprefix.h before all other includes
		else if (strcmp(arg,"-include") == 0)
		{
			argnum++;
		}

		// other parameter
		else if (arg[0] != '-' && unadorned == 0)
		{
			srcdir.cpy(arg).replacechr('/', PATH_SEPARATOR[0]);
			unadorned++;
		}
		else
			usage(argv[0]);
	}

	// make sure we got 1 parameter
	if (srcdir.len() == 0)
		usage(argv[0]);

	// recurse over subdirectories
	return recurse_dir(srcdir.len(), srcdir);
}



/***************************************************************************
    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 entry1->name.cmp(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, dependency_map &map)
{
	// skip if we're in an exclude path
	int filelen = file.name.len();
	for (exclude_path *exclude = excpaths; exclude != NULL; exclude = exclude->next)
		if (exclude->pathlen < filelen && strncmp(file.name, exclude->path, exclude->pathlen) == 0)
			if (exclude->recursive || file.name.chr(exclude->pathlen + 1, '/') == -1)
				return;

	// attempt to add; if we get an error, we're already present
	if (map.add(file.name, 0) != TMERR_NONE)
		return;

	// recurse the list from there
	for (dependency *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, astring &srcdir)
{
	static const osd_dir_entry_type typelist[] = { ENTTYPE_DIR, ENTTYPE_FILE };
	int result = 0;

	// iterate first over directories, then over files
	for (int entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++)
	{
		osd_dir_entry_type entry_type = typelist[entindex];

		// open the directory and iterate through it
		osd_directory *dir = osd_opendir(srcdir);
		if (dir == NULL)
		{
			result = 1;
			goto error;
		}

		// build up the list of files
		const osd_directory_entry *entry;
		list_entry *list = NULL;
		int found = 0;
		while ((entry = osd_readdir(dir)) != NULL)
			if (entry->type == entry_type && entry->name[0] != '.')
			{
				list_entry *lentry = new list_entry;
				lentry->name.cpy(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
		list_entry **listarray = new list_entry *[found];
		found = 0;
		for (list_entry *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];
		}
		delete[] listarray;

		// iterate through each file
		for (list_entry *curlist = list; curlist != NULL && result == 0; curlist = curlist->next)
		{
			astring srcfile;

			// build the source filename
			srcfile.printf("%s%c%s", srcdir.cstr(), PATH_SEPARATOR[0], curlist->name.cstr());

			// if we have a file, output it
			if (entry_type == ENTTYPE_FILE)
			{
				// make sure we care, first
				if (core_filename_ends_with(curlist->name, ".c"))
				{
					dependency_map depend_map;

					// find dependencies
					file_entry &file = compute_dependencies(srcrootlen, srcfile);
					recurse_dependencies(file, depend_map);

					// convert the target from source to object (makes assumptions about rules)
					astring target(file.name);
					target.replace(0, "src/", "$(OBJ)/");
					target.replace(0, ".c", ".o");
					printf("\n%s : \\\n", target.cstr());

					// iterate over the hashed dependencies and output them as well
					for (dependency_map::entry_t *entry = depend_map.first(); entry != NULL; entry = depend_map.next(entry))
						printf("\t%s \\\n", entry->tag().cstr());
				}
			}

			// if we have a directory, recurse
			else
				result = recurse_dir(srcrootlen, srcfile);
		}

		// free all the allocated entries
		while (list != NULL)
		{
			list_entry *next = list->next;
			delete list;
			list = next;
		}
	}

error:
	return result;
}


/*-------------------------------------------------
    output_file - output a file, converting to
    HTML
-------------------------------------------------*/

static file_entry &compute_dependencies(int srcrootlen, astring &srcfile)
{
	// see if we already have an entry
	astring normalfile(srcfile);
	normalfile.replacechr(PATH_SEPARATOR[0], '/');
	file_entry *foundfile = file_map.find(normalfile);
	if (foundfile != NULL)
		return *foundfile;

	// create a new header entry
	file_entry &file = *new file_entry;
	file.deplist = NULL;
	file.name = normalfile;
	file_map.add(file.name, &file);

	// read the source file
	UINT32 filelength;
	char *filedata;
	if (core_fload(srcfile, (void **)&filedata, &filelength) != FILERR_NONE)
	{
		fprintf(stderr, "Unable to read file '%s'\n", srcfile.cstr());
		return file;
	}

	// find the #include directives in this file
	for (int index = 0; index < filelength; index++)
		if (filedata[index] == '#' && strncmp(&filedata[index + 1], "include", 7) == 0)
		{
			// first make sure we're not commented or quoted
			bool just_continue = false;
			for (int scan = index; scan > 2 && filedata[scan] != 13 && filedata[scan] != 10; scan--)
				if ((filedata[scan] == '/' && filedata[scan - 1] == '/') || filedata[scan] == '"')
				{
					just_continue = true;
					break;
				}
			if (just_continue)
				continue;

			// scan forward to find the quotes or bracket
			index += 7;
			int scan;
			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;
			int start = ++scan;

			// find the closing quote
			while (scan < filelength && filedata[scan] != '"')
				scan++;
			if (scan >= filelength)
				continue;

			// find the include file
			astring filename(&filedata[start], scan - start);
			astring target;

			// create a new dependency
			if (find_include_file(target, srcrootlen, srcfile, filename))
			{
				dependency *dep = new dependency;
				dep->next = file.deplist;
				file.deplist = dep;
				dep->file = &compute_dependencies(srcrootlen, target);
			}
		}

	osd_free(filedata);
	return file;
}



/***************************************************************************
    HELPERS
***************************************************************************/

/*-------------------------------------------------
    find_include_file - find an include file
-------------------------------------------------*/

static bool find_include_file(astring &srcincpath, int srcrootlen, const astring &srcfile, const astring &filename)
{
	// iterate over include paths and find the file
	for (include_path *curpath = incpaths; curpath != NULL; curpath = curpath->next)
	{
		// a '.' include path is specially treated
		if (curpath->path == ".")
			srcincpath.cpysubstr(srcfile, 0, srcfile.rchr(0, PATH_SEPARATOR[0]));
		else
			srcincpath.cpy(curpath->path);

		// append the filename piecemeal to account for directories
		int lastsepindex = 0;
		int sepindex;
		while ((sepindex = filename.chr(lastsepindex, '/')) != -1)
		{
			astring pathpart(filename, lastsepindex, sepindex - lastsepindex);

			// handle .. by removing a chunk from the incpath
			if (pathpart == "..")
			{
				int sepindex_part = srcincpath.rchr(0, PATH_SEPARATOR[0]);
				if (sepindex_part != -1)
					srcincpath.substr(0, sepindex_part);
			}

			// otherwise, append a path separator and the pathpart
			else
				srcincpath.cat(PATH_SEPARATOR).cat(pathpart);

			// advance past the previous index
			lastsepindex = sepindex + 1;
		}

		// now append the filename
		srcincpath.cat(PATH_SEPARATOR).catsubstr(filename, lastsepindex, -1);

		// see if we can open it
		core_file *testfile;
		if (core_fopen(srcincpath, OPEN_FLAG_READ, &testfile) == FILERR_NONE)
		{
			// close the file
			core_fclose(testfile);
			return true;
		}
	}
	return false;
}