[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tyndur-devel] [PATCH v2] build hinzugefuegt



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