Tools/udibuild - Working (but hacky) udibuild tool
authorJohn Hodge <[email protected]>
Tue, 1 Oct 2013 07:48:59 +0000 (15:48 +0800)
committerJohn Hodge <[email protected]>
Tue, 1 Oct 2013 07:48:59 +0000 (15:48 +0800)
Tools/udibuild/src/Makefile [new file with mode: 0644]
Tools/udibuild/src/build.c [new file with mode: 0644]
Tools/udibuild/src/include/build.h [new file with mode: 0644]
Tools/udibuild/src/include/inifile.h [new file with mode: 0644]
Tools/udibuild/src/include/udiprops.h [new file with mode: 0644]
Tools/udibuild/src/inifile.c [new file with mode: 0644]
Tools/udibuild/src/main.c [new file with mode: 0644]
Tools/udibuild/src/udiprops.c [new file with mode: 0644]
Tools/udibuild/udibuild.ini [new file with mode: 0644]

diff --git a/Tools/udibuild/src/Makefile b/Tools/udibuild/src/Makefile
new file mode 100644 (file)
index 0000000..970dc5c
--- /dev/null
@@ -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 (file)
index 0000000..ed5d528
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * build.c
+ * - Compilation functions
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#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 (file)
index 0000000..aaad075
--- /dev/null
@@ -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 (file)
index 0000000..dce416f
--- /dev/null
@@ -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 (file)
index 0000000..5849ddc
--- /dev/null
@@ -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 (file)
index 0000000..ce91c62
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * inifile.c
+ * - .ini file parsing
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#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 (file)
index 0000000..06ac58d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Core
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>    // getopt
+#include <getopt.h>
+#include <assert.h>
+#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 <dir>)
+       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 (file)
index 0000000..c1ddf1c
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * udibuild - UDI Compilation Utility
+ * - By John Hodge (thePowersGang)
+ *
+ * udiprops.c
+ * - udiprops.txt parsing (for udibuild only)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <ctype.h>
+#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 (file)
index 0000000..8096383
--- /dev/null
@@ -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

UCC git Repository :: git.ucc.asn.au