On Sun, Mar 29 20:12, Kevin Wolf wrote: > + build: Erster Commit des Buildtools fuer tyndur > --- > diff --git a/src/modules/c/build/build.c b/src/modules/c/build/build.c > new file mode 100644 > index 0000000..e043efe > --- /dev/null > +++ b/src/modules/c/build/build.c > @@ -0,0 +1,273 @@ > +/* > + * Copyright (c) 2009 The tyndur Project. All rights reserved. > + * > + * This code is derived from software contributed to the tyndur Project > + * by Kevin Wolf. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. 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. > + * 3. All advertising materials mentioning features or use of this software > + * must display the following acknowledgement: > + * This product includes software developed by the tyndur Project > + * and its contributors. > + * 4. Neither the name of the tyndur Project 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * ``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 THE COPYRIGHT HOLDERS OR > + * CONTRIBUTORS 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 <stdio.h> > +#include <string.h> > +#include <stdlib.h> > +#include <stdarg.h> > +#include <unistd.h> > + > +#include "build.h" > + > +#ifdef __LINUX__ > +static const char* cflags = "-m32 -g -O0 -Wall -fno-stack-protector -nostdinc" > + " -fno-leading-underscore -fno-omit-frame-pointer -fno-strict-aliasing" > + " -fno-builtin -c"; > +#else > +//static const char* cflags = "-c -combine"; > +static const char* cflags = "-c"; > +#endif > + > +static const char* fpcflags = "-n -Cn -CX -Tlost"; > +static const char* nasmflags = "-felf -O99"; > +static const char* gasflags = "-32"; > + > +static int dry_run = 0; Hm hier wäre doch ein Parameter nicht verkehrt, oder? > +static char* root_path; > + > +extern int verbose; Vielleicht in die build.h? > + > + > +/** > + * Fuehrt einen Shellbefehl in einem gegebenen Arbeitsverzeichnis aus > + */ > +static void do_command(const char* path, const char* binary, > + const char* args_fmt, ...) > +{ > + char* buf; > + char* buf2; > + char* dirname; > + va_list ap; > + > + asprintf(&dirname, "%s/%s", root_path, path); > + if (verbose) { > + printf(">>> cd %s\n", dirname); > + } > + chdir(dirname); Den dirname gibst du absichlich nicht frei? ;-) > + > + va_start(ap, args_fmt); > + vasprintf(&buf, args_fmt, ap); > + va_end(ap); > + > + asprintf(&buf2, "%s %s", binary, buf); > + > + if (verbose) { > + printf(">>> %s\n", buf2); > + } > + if (!dry_run) { > + system(buf2); > + } > + > + free(buf); > + free(buf2); > + chdir(root_path); > +} > + > +/** > + * Sammelt alle Objektdateien in einem gegebenen Pfad ein und gibt sie durch > + * Leerzeichen getrennt zurueck. > + * > + * FIXME Mit Leerzeichen im Dateinamen ist das offensichtlich kaputt > + */ > +static char* get_obj_files(const char* path) > +{ > + struct build_dir* dir; > + struct build_dir* subdir; > + struct build_file* file; > + char* tmp = NULL; > + char* subdir_files; > + char* file_list = strdup(""); > + int i; > + > + dir = scan_directory(NULL, path); > + for (i = 0; (file = list_get_element_at(dir->obj_files, i)); i++) { > + tmp = file_list; > + asprintf(&file_list, "%s %s/%s", tmp, dir->path, file->name); > + free(tmp); > + } > + > + for (i = 0; (subdir = list_get_element_at(dir->subdirs, i)); i++) { > + tmp = file_list; > + subdir_files = get_obj_files(subdir->path); > + asprintf(&file_list, "%s %s", tmp, subdir_files); > + free(subdir_files); > + free(tmp); > + } dir freigeben > + > + return file_list; > +} > + > +/** > + * Kompiliert eine Anzahl von Dateien > + * > + * @param path Arbeitsverzeichnis > + * @param files Liste von zu kompilierenden Dateinamen > + * @param compiler Dateiname des Compilers > + * @param flags Flags, die in den Aufruf eingebunden werden sollen > + * @param include Zusaezlicher String, der in den Aufruf eingebunden werden > + * soll; primaer fuer die Angabe von Includeverzeichnissen. > + */ > +static void compile(const char* path, list_t* files, const char* compiler, > + const char* flags, const char* include) > +{ > + struct build_file* file; > + char* file_list = strdup(""); > + char* tmp; > + int i; > + > + for (i = 0; (file = list_get_element_at(files, i)); i++) { > + tmp = file_list; > + asprintf(&file_list, "%s %s", tmp, file->name); > + free(tmp); > + } > + > + if (*file_list) { > + do_command(path, compiler, "%s -I %s/%s %s %s", > + flags, root_path, path, include, file_list); > + } > +} > + > +/** > + * Baut ein Projektverzeichnis > + * > + * @param dir Verzeichnis, das gebaut werden soll > + * @param parent_include Includeverzeichnisse des Vaterverzeichnisses, die fuer > + * Quellcodedateien in diesem Verzeichnis zur Verfuegung stehen sollen > + * @param parent_lib lib-Verzeichnisse der Vaterverzeichnisse, deren > + * Bibliotheken in diesem Verzeichnis zur Verfuegung stehen sollen > + * @param depth Verschachtelungstiefe ausgehend vom Wurzelverzeichnis, in dem > + * gebaut wird (fuer Baumdarstellung) > + */ > +static void do_build(struct build_dir* dir, const char* parent_include, > + const char* parent_lib, int depth) > +{ > + char* include; > + char* lib; > + char* tmp = NULL; > + > + char* objs; > + struct build_dir* subdir; > + struct build_file* file; > + int i; > + > + for (i = 0; i < depth; i++) { > + printf("| "); > + } > + printf("+ %s\n", dir->path); > + > + // Ggf. include-Verzeichnis anhaengen > + if (dir->has_include) { > + asprintf(&include, "%s -I %s/%s/include", > + parent_include, root_path, dir->path); > + } else { > + include = strdup(parent_include); > + } > + > + if (dir->has_arch_include) { > + tmp = include; > + asprintf(&include, "%s -I %s/%s/include/arch/%s", > + tmp, root_path, dir->path, arch); > + free(tmp); > + } > + > + // Ggf. Lib-Verzeichnis anhaengen > + if (dir->lib != NULL) { > + asprintf(&lib, "%s %s/%s/lib/library.a", > + parent_lib, root_path, dir->path); > + } else { > + lib = strdup(parent_lib); > + } > + > + // lib-Verzeichnis wird als erstes kompiliert > + if (dir->lib) { > + do_build(dir->lib, include, lib, depth + 1); > + objs = get_obj_files(dir->lib->path); > + do_command(".", "ar", "rs %s/library.a %s", Ist man da wirklich immer in root_dir? Auch wenn das lib-Verzeichnis in einem Unterverzeichnis war? > + dir->lib->path, objs); > + free(objs); > + } > + > + // Dann alle anderen Unterverzeichnisse > + for (i = 0; (subdir = list_get_element_at(dir->subdirs, i)); i++) { > + do_build(subdir, include, lib, depth + 1); > + } > + > + // Und schliesslich noch die einzelnen Dateien > + // TODO Pruefen, ob sich Abhaengigkeiten veraendert haben > + printf("%s: Kompilieren (C)...", dir->path); > + fflush(stdout); > + compile(dir->path, dir->src_files[LANG_C], "gcc", cflags, include); > + > + printf("\r%s: Kompilieren (Pascal)...\033[K", dir->path); > + fflush(stdout); > + compile(dir->path, dir->src_files[LANG_PAS], "fpc", fpcflags, include); > + > + printf("\r%s: Assemblieren (gas)...\033[K", dir->path); > + fflush(stdout); > + compile(dir->path, dir->src_files[LANG_ASM_GAS], "as", gasflags, include); > + > + for (i = 0; (file = list_get_element_at(dir->src_files[LANG_ASM_NASM], i)); i++) { > + do_command(dir->path, "nasm", "%s %s", nasmflags, file->name); > + } > + > + // Im Wurzelverzeichnis wird gelinkt (TODO einstellbar machen) > + if (dir->parent == NULL) { > + printf("\r%s: Linken...\033[K", dir->path); > + fflush(stdout); > + > + objs = get_obj_files(dir->path); > + do_command(".", "gcc", "-o %s/run %s %s", dir->path, lib, objs); > + free(objs); > + } > + > + printf("\r\033[K"); > + fflush(stdout); > + > + free(include); > + free(lib); > +} > + > +/** > + * Bauen! > + * > + * @param root Wurzelverzeichnis des Projekts > + */ > +void build(struct build_dir* root) > +{ > + root_path = getcwd(NULL, 0); > + do_build(root, "", "", 0); > + printf("Fertig gebaut.\n"); > + free(root_path); > +} > diff --git a/src/modules/c/build/dir.c b/src/modules/c/build/dir.c > new file mode 100644 > index 0000000..83d72e8 > --- /dev/null > +++ b/src/modules/c/build/dir.c > @@ -0,0 +1,201 @@ > +/* > + * Copyright (c) 2009 The tyndur Project. All rights reserved. > + * > + * This code is derived from software contributed to the tyndur Project > + * by Kevin Wolf. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. 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. > + * 3. All advertising materials mentioning features or use of this software > + * must display the following acknowledgement: > + * This product includes software developed by the tyndur Project > + * and its contributors. > + * 4. Neither the name of the tyndur Project 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * ``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 THE COPYRIGHT HOLDERS OR > + * CONTRIBUTORS 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 <dirent.h> > +#include <stdio.h> > +#include <string.h> > +#include <stdlib.h> > +#include <sys/stat.h> > + > +#include "build.h" > + > +/** > + * Durchsucht ein Verzeichnis und speichert alle fuer das Bauen noetige > + * Informationen in einer per malloc angelegten struct build_dir, die > + * zurueckgegeben wird und vom Aufrufer freigegeben werden muss. Hm nur die Struktur selbst freigeben führt aber noch immer zu leaks, oder? Vielleicht eine Funktion fürs saubere Freigeben? > + * > + * Das bedeutet: > + * - Alle Quellcodedateien sammeln (*.c, *.pas, ...) > + * - Includeverzeichnisse speichern > + * - lib-Verzeichnisse erfassen > + * - Bei arch/-Verzeichnissen nur die richtige Architektur beruecksichtigen > + * - .nobuild und .ignorenobuild beachten > + */ > +struct build_dir* scan_directory(struct build_dir* parent, const char* path) > +{ > + DIR* dir = opendir(path); > + struct dirent* ent; > + char* suffix; > + struct build_file* file; > + enum filetype filetype; > + struct stat stat_buf; > + struct build_dir* build_dir; > + struct build_dir* subdir; > + char* file_path; > + int i; > + > + int nobuild = 0; > + int ignorenobuild = 0; > + > + if (dir == NULL) { > + fprintf(stderr, "Verzeichnis %s kann nicht geoeffnet werden.\n", > + path); > + return NULL; > + } > + > + // Speicher fuer Verzeichnis-struct anlegen und initialiseren > + build_dir = calloc(1, sizeof(*build_dir)); > + build_dir->path = strdup(path); > + build_dir->parent = parent; > + build_dir->subdirs = list_create(); > + build_dir->obj_files = list_create(); > + for (i = 0; i < MAX_LANG; i++) { > + build_dir->src_files[i] = list_create(); > + } > + > + // Dateien und Unterverzeichnisse einlesen > + while ((ent = readdir(dir))) { > + > + filetype = OTHER_FILE; > + suffix = strrchr(ent->d_name, '.'); > + > + asprintf(&file_path, "%s/%s", path, ent->d_name); > + stat(file_path, &stat_buf); > + > + // Dateityp erkennen > + if (!strcmp(ent->d_name, ".nobuild")) { > + nobuild = 1; > + goto next; > + } else if (!strcmp(ent->d_name, ".ignorenobuild")) { > + ignorenobuild = 1; > + goto next; > + } else if (*ent->d_name == '.') { > + goto next; > + } else if (S_ISDIR(stat_buf.st_mode)) { > + filetype = SUBDIR; > + } else if (suffix == NULL) { > + filetype = OTHER_FILE; > + } else if (!strcmp(suffix, ".o")) { > + filetype = OBJ; > + } else if (!strcmp(suffix, ".c")) { > + filetype = LANG_C; > + } else if (!strcmp(suffix, ".pas")) { > + filetype = LANG_PAS; > + } else if (!strcmp(suffix, ".asm")) { > + filetype = LANG_ASM_NASM; > + } else if (!strcmp(suffix, ".S")) { > + filetype = LANG_ASM_GAS; > + } > + > + // Wenn bis hierher nichts verwertbares gefunden wurde, wird die Datei > + // einfach ignoriert. > + if (filetype == OTHER_FILE) { > + goto next; > + } > + > + // Datei je nach Typ verarbeiten > + file = calloc(1, sizeof(*file)); > + file->type = LANG_ASM_GAS; Wozu ist denn das gut? > + file->name = strdup(ent->d_name); > + > + switch (filetype) { > + case SUBDIR: > + // Unterverzeichnisse werden je nach Namen unterschiedlich > + // erfasst: > + // > + // - include/ wird zu den Includepfaden hinzugefuegt, das > + // Verzeicnis wird nicht weiter durchsucht > + // - In include/arch/ und arch/ wird nur das richtige > + // Unterverzeichnis weiterverfolgt > + // - lib/ wird gesondert gespeichert, damit es vor allen > + // anderen Verzeichnissen gebaut werden kann > + // - Alles andere wird einfach als Unterverzeichnis gemerkt > + if (!strcmp(file->name, "include")) { > + DIR* arch_dir; > + char* tmp; > + > + build_dir->has_include = 1; > + > + asprintf(&tmp, "include/arch/%s", arch); > + arch_dir = opendir(tmp); > + free(tmp); > + > + if (arch_dir != NULL) { > + closedir(arch_dir); > + build_dir->has_arch_include = 1; > + } > + > + } else if (!strcmp(file->name, "lib")) { > + build_dir->lib = scan_directory(build_dir, file_path); > + } else if (!strcmp(file->name, "arch")) { > + char* tmp; > + asprintf(&tmp, "%s/%s", file_path, arch); > + subdir = scan_directory(build_dir, tmp); > + free(tmp); > + if (subdir != NULL) { > + list_push(build_dir->subdirs, subdir); > + } > + } else { > + subdir = scan_directory(build_dir, file_path); > + if (subdir != NULL) { > + list_push(build_dir->subdirs, subdir); > + } > + } > + break; > + case OBJ: > + // Objektdateien haben ihre eigene Liste > + list_push(build_dir->obj_files, file); > + break; > + default: > + // Quellcodedateien werden nach Sprache getrennt gespeichert > + list_push(build_dir->src_files[filetype], file); > + break; > + } > + > + next: > + free(file_path); > + } > + > + closedir(dir); > + > + // Wenn das Verzeichnis gar nicht gebaut werden soll, besser nichts > + // zurueckgeben > + if (nobuild && !ignorenobuild) { > + // TODO Freigeben Jo, das sollte man wirklich.... ;-) > + return NULL; > + } > + > + return build_dir; > +} > diff --git a/src/modules/c/build/include/build.h b/src/modules/c/build/include/build.h > new file mode 100644 > index 0000000..f4b8614 > --- /dev/null > +++ b/src/modules/c/build/include/build.h > @@ -0,0 +1,76 @@ > +/* > + * Copyright (c) 2009 The tyndur Project. All rights reserved. > + * > + * This code is derived from software contributed to the tyndur Project > + * by Kevin Wolf. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. 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. > + * 3. All advertising materials mentioning features or use of this software > + * must display the following acknowledgement: > + * This product includes software developed by the tyndur Project > + * and its contributors. > + * 4. Neither the name of the tyndur Project 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * ``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 THE COPYRIGHT HOLDERS OR > + * CONTRIBUTORS 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. > + */ > + > +#ifndef _BUILD_H_ > +#define _BUILD_H_ > + > +#include "collections.h" Haben wir uns hier nicht mal auf <> geeinigt? Oder habe ich das falsch in Erinnerung? > + > +enum filetype { > + LANG_C, > + LANG_PAS, > + LANG_ASM_GAS, > + LANG_ASM_NASM, > + > +#define MAX_LANG OTHER_FILE > + OTHER_FILE, > + SUBDIR, > + OBJ, > +}; > + > + > +extern char* filetype_str[]; > +extern char* arch; > + > +struct build_dir { > + int has_include; > + int has_arch_include; > + char* path; > + struct build_dir* parent; > + struct build_dir* lib; > + list_t* src_files[MAX_LANG]; > + list_t* obj_files; > + list_t* subdirs; > +}; > + > +struct build_file { > + enum filetype type; > + char* name; > +}; > + > +struct build_dir* scan_directory(struct build_dir* parent, const char* path); > +void build(struct build_dir* root); > + > +#endif Das ist was mir grad so auffällt. -- Antoine Kaufmann <toni@xxxxxxxxxxxxxxxx>
Attachment:
pgpG39c5Tk_cS.pgp
Description: PGP signature