From: John Hodge Date: Tue, 1 Oct 2013 07:48:59 +0000 (+0800) Subject: Tools/udibuild - Working (but hacky) udibuild tool X-Git-Tag: rel0.15~159 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=7e6b3865188ae17d8094ddff89d49086b30b9626;p=tpg%2Facess2.git Tools/udibuild - Working (but hacky) udibuild tool --- diff --git a/Tools/udibuild/src/Makefile b/Tools/udibuild/src/Makefile new file mode 100644 index 00000000..970dc5c9 --- /dev/null +++ b/Tools/udibuild/src/Makefile @@ -0,0 +1,25 @@ + +OBJS = main.o inifile.o build.o udiprops.o +BIN = ../udibuild +CFLAGS = -std=c99 -MMD -MP -g + +OBJS := $(OBJS:%=obj/%) + +.PHONY: all clean + +all: $(BIN) + +clean: + $(RM) $(BIN) $(OBJS) $(OBJS:%.o=%.d) + +$(BIN): $(OBJS) + @echo --- [CC] $@ + @$(CC) -o $(BIN) $(OBJS) $(LDFLAGS) + +obj/%.o: %.c Makefile + @mkdir -p $(dir $@) + @echo --- [CC] $@ + @$(CC) -o $@ -c $< $(CFLAGS) + +-include $(OBJS:%.o=%.d) + diff --git a/Tools/udibuild/src/build.c b/Tools/udibuild/src/build.c new file mode 100644 index 00000000..ed5d5287 --- /dev/null +++ b/Tools/udibuild/src/build.c @@ -0,0 +1,73 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * build.c + * - Compilation functions + */ +#include +#include +#include +#include "include/build.h" + +#ifndef __GNUC__ +# define __attribute__(...) +#endif + +// === PROTOTYPES === +char *get_objfile(tIniFile *opts, const char *srcfile); +char *mkstr(const char *fmt, ...) __attribute__((format(printf,1,2))); + +// === CODE === +int Build_CompileFile(tIniFile *opts, const char *abi, tUdiprops *udiprops, tUdiprops_Srcfile *srcfile) +{ + // Select compiler from opts [abi] + const char *cc_prog = IniFile_Get(opts, abi, "CC", NULL); + if( !cc_prog ) { + fprintf(stderr, "No 'CC' defined for ABI %s\n", abi); + return 1; + } + + // Build up compiler's command line + // - Include CFLAGS from .ini file + // - defines from udiprops + // - Object file is srcfile with .o appended + // > Place in 'obj/' dir? + char *objfile = get_objfile(opts, srcfile->Filename); + char *cmd = mkstr("%s -DUDI_ABI_is_%s %s %s -c %s -o %s", + cc_prog, + abi, + IniFile_Get(opts, abi, "CFLAGS", ""), + srcfile->CompileOpts ? srcfile->CompileOpts : "", + srcfile->Filename, objfile); + printf("--- Compiling: %s\n", srcfile->Filename); + int rv = system(cmd); + free(cmd); + free(objfile); + + return rv; +} + +int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops) +{ + return 0; +} + +char *get_objfile(tIniFile *opts, const char *srcfile) +{ + return mkstr("%s.o", srcfile); +} + +char *mkstr(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + size_t len = vsnprintf(NULL, 0, fmt, args); + va_end(args); + va_start(args, fmt); + char *ret = malloc(len+1); + vsnprintf(ret, len+1, fmt, args); + va_end(args); + return ret; +} + diff --git a/Tools/udibuild/src/include/build.h b/Tools/udibuild/src/include/build.h new file mode 100644 index 00000000..aaad075c --- /dev/null +++ b/Tools/udibuild/src/include/build.h @@ -0,0 +1,18 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * build.h + * - Actual build steps (exposed functions) + */ +#ifndef _BUILD_H_ +#define _BUILD_H_ + +#include "inifile.h" +#include "udiprops.h" + +extern int Build_CompileFile(tIniFile *opts, const char *abi, tUdiprops *udiprops, tUdiprops_Srcfile *srcfile); +extern int Build_LinkObjects(tIniFile *opts, const char *abi, tUdiprops *udiprops); + +#endif + diff --git a/Tools/udibuild/src/include/inifile.h b/Tools/udibuild/src/include/inifile.h new file mode 100644 index 00000000..dce416fc --- /dev/null +++ b/Tools/udibuild/src/include/inifile.h @@ -0,0 +1,18 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * inifile.h + * - .ini file parsing + */ +#ifndef _INIFILE_H_ +#define _INIFILE_H_ + +typedef struct sInifile tIniFile; + +extern tIniFile *IniFile_Load(const char *Path); +extern const char *IniFile_Get(tIniFile *File, const char *Sect, const char *Key, const char *Default); +extern void IniFile_Free(tIniFile *File); + +#endif + diff --git a/Tools/udibuild/src/include/udiprops.h b/Tools/udibuild/src/include/udiprops.h new file mode 100644 index 00000000..5849ddc6 --- /dev/null +++ b/Tools/udibuild/src/include/udiprops.h @@ -0,0 +1,29 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * udiprops.h + * - udiprops.txt parsing for udibuild + */ +#ifndef _UDIPROPS_H_ +#define _UDIPROPS_H_ + +typedef struct sUdiprops tUdiprops; + +typedef struct sUdiprops_Srcfile tUdiprops_Srcfile; + +struct sUdiprops_Srcfile +{ + const char *Filename; + const char *CompileOpts; +}; + +struct sUdiprops +{ + tUdiprops_Srcfile **SourceFiles; +}; + +extern tUdiprops *Udiprops_LoadBuild(const char *Filename); + +#endif + diff --git a/Tools/udibuild/src/inifile.c b/Tools/udibuild/src/inifile.c new file mode 100644 index 00000000..ce91c625 --- /dev/null +++ b/Tools/udibuild/src/inifile.c @@ -0,0 +1,126 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * inifile.c + * - .ini file parsing + */ +#include +#include +#include +#include +#include +#include "include/inifile.h" + +typedef struct sInifile_Section tIniFile_Section; +typedef struct sInifile_Value tIniFile_Value; + +struct sInifile_Value +{ + tIniFile_Value *Next; + const char *Key; + const char *Value; +}; + +struct sInifile_Section +{ + tIniFile_Section *Next; + const char *Name; + tIniFile_Value *FirstValue; +}; + +struct sInifile +{ + tIniFile_Section RootSection; +}; + +// === CODE === +static void rtrim(char *str) +{ + char *pos = str; + while( *pos ) + pos ++; + while( pos != str && isspace(pos[-1]) ) + *--pos = '\0'; +} + +tIniFile *IniFile_Load(const char *Path) +{ + FILE *fp = fopen(Path, "r"); + if( !fp ) + return NULL; + + tIniFile *ret = malloc( sizeof(tIniFile) ); + assert(ret); + + ret->RootSection.Name = ""; + ret->RootSection.FirstValue = NULL; + + tIniFile_Section *curSect = &ret->RootSection; + char buf[512]; + while( fgets(buf, sizeof(buf)-1, fp) ) + { + rtrim(buf); + char name[64]; + size_t ofs = 0; + if( sscanf(buf, "[%[^]]]", name) == 1 ) { + //printf("section %s\n", name); + // new section + tIniFile_Section *new_sect = malloc(sizeof(tIniFile_Section)+strlen(name)+1); + new_sect->Next = NULL; + new_sect->Name = (const char*)(new_sect+1); + new_sect->FirstValue = NULL; + strcpy( (char*)new_sect->Name, name ); + curSect->Next = new_sect; + curSect = new_sect; + } + else if( sscanf(buf, "%[^=]=%n", name, &ofs) >= 1 ) { + //printf("key %s equals %s\n", name, value); + const char *value = buf + ofs; + tIniFile_Value *val = malloc(sizeof(tIniFile_Value)+strlen(name)+1+strlen(value)+1); + val->Next = curSect->FirstValue; + curSect->FirstValue = val; + + val->Key = (char*)(val+1); + strcpy((char*)val->Key, name); + val->Value = val->Key + strlen(val->Key) + 1; + strcpy((char*)val->Value, value); + } + else { + //printf("ignore %s\n", buf); + // ignore + } + } + + fclose(fp); + + return ret; +} + +const char *IniFile_Get(tIniFile *File, const char *Sect, const char *Key, const char *Default) +{ + tIniFile_Section *sect; + for( sect = &File->RootSection; sect; sect = sect->Next ) + { + if( strcmp(sect->Name, Sect) == 0 ) + break; + } + if( !sect ) + return Default; + + tIniFile_Value *val; + for( val = sect->FirstValue; val; val = val->Next ) + { + if( strcmp(val->Key, Key) == 0 ) + break; + } + if( !val ) + return Default; + + return val->Value; +} + +void IniFile_Free(tIniFile *File) +{ + // TODO: +} diff --git a/Tools/udibuild/src/main.c b/Tools/udibuild/src/main.c new file mode 100644 index 00000000..06ac58d4 --- /dev/null +++ b/Tools/udibuild/src/main.c @@ -0,0 +1,130 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * main.c + * - Core + */ +#include +#include +#include // getopt +#include +#include +#include "include/build.h" +#include "include/inifile.h" +#include "include/udiprops.h" + +#ifdef __ACESS__ +#define CONFIG_FILE "/Acess/Conf/UDI/udibuild.ini" +#else +#define CONFIG_FILE "/etc/udi/udibuild.ini" +#endif + +// === PROTOTYPES === + int main(int argc, char *argv[]); + int ParseArguments(int argc, char *argv[]); +void Usage(const char *progname); + +// === GLOBALS === +const char *gsOpt_ConfigFile; +const char *gsOpt_WorkingDir; +const char *gsOpt_UdipropsFile; +const char *gsOpt_ABIName = "ia32"; +tIniFile *gpOptions; +tUdiprops *gpUdipropsBuild; + +// === CODE === +int main(int argc, char *argv[]) +{ + if( ParseArguments(argc, argv) ) { + return 1; + } + + // Locate udibuild.ini + if( NULL == gsOpt_ConfigFile ) + { + // 1. Check CWD + //if( file_exists("./udibuild.ini") ) + //{ + // gsOpt_ConfigFile = "udibuild.ini"; + //} + // 2. Check program dir (if not invoked from PATH) + // 3. Check ~/.config/udi/udibuild.ini + // 4. Check CONFIGNAME + + exit(2); + } + gpOptions = IniFile_Load(gsOpt_ConfigFile); + assert(gpOptions); + + // Change to working directory (-C ) + if( gsOpt_WorkingDir ) + { + chdir(gsOpt_WorkingDir); + } + + // Load udiprops + gpUdipropsBuild = Udiprops_LoadBuild( gsOpt_UdipropsFile ? gsOpt_UdipropsFile : "udiprops.txt" ); + assert(gpUdipropsBuild); + assert(gpUdipropsBuild->SourceFiles); + + // Do build + for( int i = 0; gpUdipropsBuild->SourceFiles[i]; i ++ ) + { + int rv = Build_CompileFile(gpOptions, gsOpt_ABIName, gpUdipropsBuild, + gpUdipropsBuild->SourceFiles[i]); + if( rv ) { + fprintf(stderr, "*** Exit status: %i\n", rv); + return rv; + } + } + Build_LinkObjects(gpOptions, gsOpt_ABIName, gpUdipropsBuild); + + return 0; +} + +int ParseArguments(int argc, char *argv[]) +{ + int opt; + while( (opt = getopt(argc, argv, "hC:c:f:a:")) != -1 ) + { + switch(opt) + { + case 'h': + Usage(argv[0]); + exit(0); + case 'C': + gsOpt_WorkingDir = optarg; + break; + case 'c': + gsOpt_ConfigFile = optarg; + break; + case 'f': + gsOpt_UdipropsFile = optarg; + break; + case 'a': + gsOpt_ABIName = optarg; + break; + case '?': + Usage(argv[0]); + return 1; + default: + fprintf(stderr, "BUG: Unhandled optarg %i '%c'\n", opt, opt); + break; + } + } + return 0; +} + +void Usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [-C workingdir] [-c udibuild.ini] [-f udiprops.txt] [-a abiname]\n", + progname); + fprintf(stderr, "\n" + "-C workingdir : Change to the specified directory before looking for udiprops.txt\n" + "-c udibuild.ini : Override the default udibuild config file\n" + "-f udiprops.txt : Override the default udiprops file\n" + "-a abiname : Select a different ABI\n" + "\n"); +} + diff --git a/Tools/udibuild/src/udiprops.c b/Tools/udibuild/src/udiprops.c new file mode 100644 index 00000000..c1ddf1c0 --- /dev/null +++ b/Tools/udibuild/src/udiprops.c @@ -0,0 +1,114 @@ +/* + * udibuild - UDI Compilation Utility + * - By John Hodge (thePowersGang) + * + * udiprops.c + * - udiprops.txt parsing (for udibuild only) + */ +#include +#include +#include +#include +#include +#include +#include "include/udiprops.h" + +// === CODE === +static int _get_token_sym(const char *str, const char **outstr, ...) +{ + va_list args; + va_start(args, outstr); + const char *sym; + for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ ) + { + size_t len = strlen(sym); + if( memcmp(str, sym, len) != 0 ) + continue ; + if( str[len] && !isspace(str[len]) ) + continue ; + + // Found it! + *outstr = str + len; + while( isspace(**outstr) ) + (*outstr) ++; + return idx; + } + va_end(args); + + const char *end = str; + while( !isspace(*end) ) + end ++; +// fprintf(stderr, "udiprops: Unknown token '%.*s'\n", end-str, str); + + *outstr = NULL; + return -1; +} + +static void rtrim(char *str) +{ + char *pos = str; + while( *pos ) + pos ++; + while( pos != str && isspace(pos[-1]) ) + *--pos = '\0'; +} + +tUdiprops *Udiprops_LoadBuild(const char *Filename) +{ + FILE *fp = fopen(Filename, "r"); + if( !fp ) { + perror("Udiprops_LoadBuild"); + return NULL; + } + + char *current_compile_opts = NULL; + int n_srcfiles = 0; + tUdiprops *ret = calloc( 1, sizeof(tUdiprops) ); + + char buf[512]; + while( fgets(buf, sizeof(buf)-1, fp) ) + { + char *str = buf; + { + char *hash = strchr(str, '#'); + if( hash ) *hash = '\0'; + } + rtrim(str); + if( !str[0] ) continue ; + + int sym = _get_token_sym(str, (const char**)&str, + "source_files", "compile_options", "source_requires", NULL); + switch(sym) + { + case 0: // source_files + for(char *file = strtok(str, " \t"); file; file = strtok(NULL, " \t") ) + { + tUdiprops_Srcfile *srcfile = malloc(sizeof(tUdiprops_Srcfile)+strlen(file)+1); + srcfile->CompileOpts = current_compile_opts; + srcfile->Filename = (void*)(srcfile+1); + strcpy((char*)srcfile->Filename, file); + + n_srcfiles ++; + ret->SourceFiles = realloc(ret->SourceFiles, (n_srcfiles+1)*sizeof(void*)); + ret->SourceFiles[n_srcfiles-1] = srcfile; + ret->SourceFiles[n_srcfiles] = NULL; + } + break; + case 1: // compile_options + current_compile_opts = malloc(strlen(str)+1); + strcpy(current_compile_opts, str); + break; + case 2: // source_requires + // TODO: Use source_requires + break; + } + } + + // "Intentional" memory leak + // - current_compile_opts not freed, and shared between srcfiles + // - If two compile_options statements appear in a row, one is definitely leaked + + fclose(fp); + return ret; +} + diff --git a/Tools/udibuild/udibuild.ini b/Tools/udibuild/udibuild.ini new file mode 100644 index 00000000..80963830 --- /dev/null +++ b/Tools/udibuild/udibuild.ini @@ -0,0 +1,6 @@ +[COMMON] + +[ia32] +CFLAGS=-ffreestanding -I/home/tpg/Projects/GitClones/acess2/KernelLand/Modules/Interfaces/UDI/include/ +CC=i586-elf-gcc +LD=i586-elf-ld