shithub: mc

Download patch

ref: 66927662264ccbcdf60396c156d1964d35b41ece
parent: afc7520151f5ea1c30be31e9eb85e58dd863d632
author: Ori Bernstein <[email protected]>
date: Fri Dec 27 13:53:03 EST 2013

Handle link order.

    Fuck link order.

--- a/myrbuild/myrbuild.c
+++ b/myrbuild/myrbuild.c
@@ -33,9 +33,8 @@
 /* additional paths to search for packages */
 char **incpaths;
 size_t nincpaths;
-/* libraries to link against. */
-char **libs;
-size_t nlibs;
+/* libraries to link against, and their deps */
+Htab *libgraph;  /* string -> null terminated string list */
 /* the linker script to use */
 char *ldscript;
 
@@ -42,8 +41,8 @@
 char *sysname;
 
 regex_t usepat;
-Htab *compiled;
-Htab *loopdetect;
+Htab *compiled; /* used as string set */
+Htab *loopdetect; /* used as string set */
 
 static void usage(char *prog)
 {
@@ -185,6 +184,50 @@
     *ndeps = i;
 }
 
+FILE *openlib(char *lib)
+{
+    FILE *f;
+    char buf[1024];
+    size_t i;
+
+    snprintf(buf, sizeof buf, "%s/%s/%s", Instroot, "/lib/myr", lib);
+    f = fopen(buf, "r");
+    if (f)
+        return f;
+    for (i = 0; i < nincpaths; i++) {
+        snprintf(buf, sizeof buf, "%s/%s", incpaths[i], lib);
+        f = fopen(buf, "r");
+        if (f)
+            return f;
+    }
+    err(1, "could not open library file %s\n", lib);
+}
+
+void scrapelib(Htab *g, char *lib)
+{
+    char **deps;
+    size_t ndeps;
+    FILE *use;
+    char *l;
+
+    if (hthas(libgraph, lib))
+        return;
+    deps = NULL;
+    ndeps = 0;
+    use = openlib(lib);
+    if (fgetc(use) != 'U')
+        err(1, "library \"%s\" is not a usefile.", lib);
+    /* we don't care about the usefile's name */
+    free(rdstr(use));
+    while (fgetc(use) == 'L') {
+        l = rdstr(use);
+        lappend(&deps, &ndeps, l);
+        scrapelib(g, l);
+    }
+    lappend(&deps, &ndeps, NULL);
+    htput(g, lib, deps);
+}
+
 void compile(char *file)
 {
     size_t i, ndeps;
@@ -211,8 +254,8 @@
                 localdep = usetomyr(deps[i]);
                 compile(localdep);
                 free(localdep);
-            } else if (!inlist(libs, nlibs, deps[i])) {
-                lappend(&libs, &nlibs, deps[i]);
+            } else {
+                scrapelib(libgraph, deps[i]);
             }
         }
         if (isfresh(file, use))
@@ -296,6 +339,44 @@
     lfree(&args, &nargs);
 }
 
+void visit(char ***args, size_t *nargs, size_t head, Htab *g, char *n, Htab *looped, Htab *marked)
+{
+    char **deps;
+    char buf[1024];
+
+    if (hthas(looped, n))
+        err(1, "cycle in library dependency graph involving %s\n", n);
+    if (hthas(marked, n))
+        return;
+    htput(looped, n, n);
+    for (deps = htget(g, n); *deps; deps++)
+        visit(args, nargs, head, g, *deps, looped, marked);
+    htdel(looped, n);
+    htput(marked, n, n);
+    snprintf(buf, sizeof buf, "-l%s", n);
+    linsert(args, nargs, head, strdup(buf));
+}
+
+/* topologically sorts the dependency graph of the libraries. */
+void addlibs(char ***args, size_t *nargs, Htab *g)
+{
+    void **libs;
+    size_t nlibs;
+    size_t i;
+    size_t head;
+    Htab *looped;
+    Htab *marked;
+
+    libs = htkeys(g, &nlibs);
+    looped = mkht(strhash, streq);
+    marked = mkht(strhash, streq);
+    head = *nargs;
+    for (i = 0; i < nlibs; i++)
+        visit(args, nargs, head, g, libs[i], looped, marked);
+    compiled = mkht(strhash, streq);
+    
+}
+
 void linkobj(char **files, size_t nfiles)
 {
     char **args;
@@ -339,10 +420,7 @@
     lappend(&args, &nargs, strdup(buf));
 
     /* ld -T ldscript -o outfile foo.o bar.o baz.o -L/path1 -L/path2 -llib1 -llib2*/
-    for (i = 0; i < nlibs; i++) {
-        snprintf(buf, sizeof buf, "-l%s", libs[i]);
-        lappend(&args, &nargs, strdup(buf));
-    }
+    addlibs(&args, &nargs, libgraph);
 
     /* OSX wants a minimum version specified to prevent warnings*/
     if (!strcmp(sysname, "Darwin")) {
@@ -395,6 +473,7 @@
     if (libname && binname)
         die("Can't specify both library and binary names");
 
+    libgraph = mkht(strhash, streq);
     compiled = mkht(strhash, streq);
     loopdetect = mkht(strhash, streq);
     regcomp(&usepat, "^[[:space:]]*use[[:space:]]+([^[:space:]]+)", REG_EXTENDED);
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -162,6 +162,8 @@
             char  *name;
             size_t nuses;
             Node **uses;
+            size_t nlibdeps;
+            char **libdeps;
             size_t nstmts;
             Node **stmts;
             Stab  *globls;
--- a/parse/use.c
+++ b/parse/use.c
@@ -663,6 +663,7 @@
     Node *dcl;
     Stab *s;
     Type *t;
+    char *lib;
     int c;
 
     pushstab(file->file.globls);
@@ -690,6 +691,14 @@
     tidmap = mkht(ptrhash, ptreq);
     while ((c = fgetc(f)) != EOF) {
         switch(c) {
+            case 'L':
+                lib = rdstr(f);
+                for (i = 0; i < file->file.nlibdeps; i++)
+                    if (!strcmp(file->file.libdeps[i], lib))
+                        goto foundlib;
+                lappend(&file->file.libdeps, &file->file.nlibdeps, lib);
+foundlib:
+                break;
             case 'G':
             case 'D':
                 dcl = rdsym(f);
@@ -764,15 +773,31 @@
 {
     Stab *st;
     void **k;
-    Node *s;
+    Node *s, *u;
     size_t i, n;
 
+    assert(file->type == Nfile);
     st = file->file.exports;
+
+    /* usefile name */
     wrbyte(f, 'U');
     if (st->name)
         wrstr(f, namestr(st->name));
     else
         wrstr(f, NULL);
+
+    /* library deps */
+    for (i = 0; i < file->file.nuses; i++) {
+        u = file->file.uses[i];
+        if (!u->use.islocal) {
+            wrbyte(f, 'L');
+            wrstr(f, u->use.name);
+        }
+    }
+    for (i = 0; i < file->file.nlibdeps; i++) {
+        wrbyte(f, 'L');
+        wrstr(f, file->file.libdeps[i]);
+    }
 
     for (i = 0; i < ntypes; i++) {
         if (types[i]->vis == Visexport || types[i]->vis == Vishidden) {