/* $Id$ */ /* Copyright (c) 2006-2016 Pierre Pronchery */ /* This file is part of DeforaOS Devel configure */ /* All rights reserved. * * 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. * * 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 * HOLDER 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 #include #include #include #include #include #include #include #include "settings.h" #include "configure.h" #include "../config.h" #ifndef PROGNAME # define PROGNAME PACKAGE #endif /* prototypes */ /* accessors */ static int _makefile_is_phony(Configure * configure, char const * target); /* useful */ static int _makefile_expand(FILE * fp, char const * field); static int _makefile_link(FILE * fp, int symlink, char const * link, char const * path); static int _makefile_output_variable(FILE * fp, char const * name, char const * value); static int _makefile_mkdir(FILE * fp, char const * directory); static int _makefile_print(FILE * fp, char const * format, ...); static int _makefile_remove(FILE * fp, int recursive, ...); static int _makefile_subdirs(FILE * fp, char const * target); static int _makefile_target(FILE * fp, char const * target, ...); #ifdef WITH_UNUSED static int _makefile_targetv(FILE * fp, char const * target, char const ** depends); #endif /* functions */ /* makefile */ static int _makefile_write(Configure * configure, FILE * fp, configArray * ca, int from, int to); int makefile(Configure * configure, String const * directory, configArray * ca, int from, int to) { String * makefile; FILE * fp = NULL; int ret = 0; makefile = string_new(directory); string_append(&makefile, "/"); /* FIXME check for errors */ string_append(&makefile, MAKEFILE); if(!(configure->prefs->flags & PREFS_n) && (fp = fopen(makefile, "w")) == NULL) ret = configure_error(makefile, 1); else { if(configure->prefs->flags & PREFS_v) printf("%s%s/%s", "Creating ", directory, MAKEFILE "\n"); ret |= _makefile_write(configure, fp, ca, from, to); if(fp != NULL) fclose(fp); } string_delete(makefile); return ret; } static int _write_variables(Configure * configure, FILE * fp); static int _write_targets(Configure * configure, FILE * fp); static int _write_objects(Configure * configure, FILE * fp); static int _write_clean(Configure * configure, FILE * fp); static int _write_distclean(Configure * configure, FILE * fp); static int _write_dist(Configure * configure, FILE * fp, configArray * ca, int from, int to); static int _write_distcheck(Configure * configure, FILE * fp); static int _write_install(Configure * configure, FILE * fp); static int _write_phony(Configure * configure, FILE * fp, char const ** targets); static int _write_uninstall(Configure * configure, FILE * fp); static int _makefile_write(Configure * configure, FILE * fp, configArray * ca, int from, int to) { Config * config = configure->config; char const * depends[9] = { "all" }; size_t i = 1; if(_write_variables(configure, fp) != 0 || _write_targets(configure, fp) != 0 || _write_objects(configure, fp) != 0 || _write_clean(configure, fp) != 0 || _write_distclean(configure, fp) != 0 || _write_dist(configure, fp, ca, from, to) != 0 || _write_distcheck(configure, fp) != 0 || _write_install(configure, fp) != 0 || _write_uninstall(configure, fp) != 0) return 1; if(config_get(config, NULL, "subdirs") != NULL) depends[i++] = "subdirs"; depends[i++] = "clean"; depends[i++] = "distclean"; if(config_get(config, NULL, "package") != NULL && config_get(config, NULL, "version") != NULL) { depends[i++] = "dist"; depends[i++] = "distcheck"; } depends[i++] = "install"; depends[i++] = "uninstall"; depends[i++] = NULL; return _write_phony(configure, fp, depends); } static int _variables_package(Configure * configure, FILE * fp, String const * directory); static int _variables_print(Configure * configure, FILE * fp, char const * input, char const * output); static int _variables_dist(Configure * configure, FILE * fp); static int _variables_targets(Configure * configure, FILE * fp); static int _variables_targets_library(Configure * configure, FILE * fp, char const * target); static int _variables_executables(Configure * configure, FILE * fp); static int _variables_includes(Configure * configure, FILE * fp); static int _variables_subdirs(Configure * configure, FILE * fp); static int _write_variables(Configure * configure, FILE * fp) { int ret = 0; String const * directory; directory = config_get(configure->config, NULL, "directory"); ret |= _variables_package(configure, fp, directory); ret |= _variables_print(configure, fp, "subdirs", "SUBDIRS"); ret |= _variables_dist(configure, fp); ret |= _variables_targets(configure, fp); ret |= _variables_executables(configure, fp); ret |= _variables_includes(configure, fp); ret |= _variables_subdirs(configure, fp); _makefile_print(fp, "%c", '\n'); return ret; } static int _variables_package(Configure * configure, FILE * fp, String const * directory) { String const * package; String const * version; String const * p; if((package = config_get(configure->config, NULL, "package")) == NULL) return 0; if(configure->prefs->flags & PREFS_v) printf("%s%s", "Package: ", package); if((version = config_get(configure->config, NULL, "version")) == NULL) { if(configure->prefs->flags & PREFS_v) fputc('\n', stdout); fprintf(stderr, "%s%s%s", PROGNAME ": ", directory, ": \"package\" needs \"version\"\n"); return 1; } if(configure->prefs->flags & PREFS_v) printf(" %s\n", version); _makefile_output_variable(fp, "PACKAGE", package); _makefile_output_variable(fp, "VERSION", version); if((p = config_get(configure->config, NULL, "config")) != NULL) return settings(configure->prefs, configure->config, directory, package, version); return 0; } static int _variables_print(Configure * configure, FILE * fp, char const * input, char const * output) { String const * p; String * prints; String * q; unsigned long i; char c; if((p = config_get(configure->config, NULL, input)) == NULL) return 0; if((prints = string_new(p)) == NULL) return 1; q = prints; _makefile_print(fp, "%s%s", output, "\t="); for(i = 0;; i++) { if(prints[i] != ',' && prints[i] != '\0') continue; c = prints[i]; prints[i] = '\0'; if(strchr(prints, ' ') != NULL) _makefile_print(fp, " \"%s\"", prints); else _makefile_print(fp, " %s", prints); if(c == '\0') break; prints += i + 1; i = 0; } _makefile_print(fp, "%c", '\n'); string_delete(q); return 0; } static int _variables_dist(Configure * configure, FILE * fp) { String const * p; String * dist; String * q; size_t i; char c; if((p = config_get(configure->config, NULL, "dist")) == NULL) return 0; if((dist = string_new(p)) == NULL) return 1; q = dist; for(i = 0;; i++) { if(dist[i] != ',' && dist[i] != '\0') continue; c = dist[i]; dist[i] = '\0'; if(config_get(configure->config, dist, "install") != NULL) { /* FIXME may still need to be output */ if(config_get(configure->config, NULL, "targets") == NULL) { _makefile_output_variable(fp, "OBJDIR", ""); _makefile_output_variable(fp, "PREFIX", configure->prefs->prefix); _makefile_output_variable(fp, "DESTDIR", configure->prefs->destdir); } _makefile_output_variable(fp, "MKDIR", configure->programs.mkdir); _makefile_output_variable(fp, "INSTALL", configure->programs.install); _makefile_output_variable(fp, "RM", configure->programs.rm); break; } if(c == '\0') break; dist += i + 1; i = 0; } string_delete(q); return 0; } static int _variables_targets(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * prints; String * q; size_t i; char c; String const * type; int phony; if((p = config_get(configure->config, NULL, "targets")) == NULL) return 0; if((prints = string_new(p)) == NULL) return 1; q = prints; _makefile_print(fp, "%s", "TARGETS\t="); for(i = 0;; i++) { if(prints[i] != ',' && prints[i] != '\0') continue; c = prints[i]; prints[i] = '\0'; if((type = config_get(configure->config, prints, "type")) == NULL) _makefile_print(fp, " %s", prints); else switch(enum_string(TT_LAST, sTargetType, type)) { case TT_BINARY: _makefile_print(fp, " $(OBJDIR)%s$(EXEEXT)", prints); break; case TT_LIBRARY: ret |= _variables_targets_library( configure, fp, prints); break; case TT_LIBTOOL: _makefile_print(fp, " $(OBJDIR)%s%s", prints, ".la"); break; case TT_OBJECT: case TT_UNKNOWN: _makefile_print(fp, " $(OBJDIR)%s", prints); break; case TT_SCRIPT: phony = _makefile_is_phony(configure, prints); _makefile_print(fp, " %s%s", phony ? "" : "$(OBJDIR)", prints); break; case TT_PLUGIN: _makefile_print(fp, " $(OBJDIR)%s$(SOEXT)", prints); break; } if(c == '\0') break; prints += i + 1; i = 0; } _makefile_print(fp, "%c", '\n'); string_delete(q); return ret; } static int _variables_targets_library(Configure * configure, FILE * fp, char const * target) { String * soname; String const * p; if((p = config_get(configure->config, target, "soname")) != NULL) soname = string_new(p); else if(configure->os == HO_MACOSX) /* versioning is different on MacOS X */ soname = string_new_append(target, ".0.0$(SOEXT)", NULL); else if(configure->os == HO_WIN32) /* and on Windows */ soname = string_new_append(target, "$(SOEXT)", NULL); else soname = string_new_append(target, "$(SOEXT)", ".0", NULL); if(soname == NULL) return 1; if(configure_can_library_static(configure)) /* generate a static library */ _makefile_print(fp, "%s%s%s", " $(OBJDIR)", target, ".a"); if(configure->os == HO_MACOSX) _makefile_print(fp, "%s%s%s%s%s%s%s", " $(OBJDIR)", soname, " $(OBJDIR)", target, ".0$(SOEXT) $(OBJDIR)", target, "$(SOEXT)"); else if(configure->os == HO_WIN32) _makefile_print(fp, "%s%s", " $(OBJDIR)", soname); else _makefile_print(fp, "%s%s%s%s%s%s%s", " $(OBJDIR)", soname, ".0 $(OBJDIR)", soname, " $(OBJDIR)", target, "$(SOEXT)"); string_delete(soname); return 0; } static void _executables_variables(Configure * configure, FILE * fp, String const * target, char * done); static int _variables_executables(Configure * configure, FILE * fp) { char done[TT_LAST]; /* FIXME even better if'd be variable by variable */ String const * targets; String const * includes; String const * package; String * p; String * q; size_t i; char c; memset(&done, 0, sizeof(done)); targets = config_get(configure->config, NULL, "targets"); includes = config_get(configure->config, NULL, "includes"); package = config_get(configure->config, NULL, "package"); if(targets != NULL) { if((p = string_new(targets)) == NULL) return 1; q = p; for(i = 0;; i++) { if(p[i] != ',' && p[i] != '\0') continue; c = p[i]; p[i] = '\0'; _executables_variables(configure, fp, p, done); if(c == '\0') break; p += i + 1; i = 0; } string_delete(q); } else if(includes != NULL) { _makefile_output_variable(fp, "OBJDIR", ""); _makefile_output_variable(fp, "PREFIX", configure->prefs->prefix); _makefile_output_variable(fp, "DESTDIR", configure->prefs->destdir); } if(targets != NULL || includes != NULL || package != NULL) { _makefile_output_variable(fp, "RM", configure->programs.rm); _makefile_output_variable(fp, "LN", configure->programs.ln); } if(package != NULL) { _makefile_output_variable(fp, "TAR", configure->programs.tar); _makefile_output_variable(fp, "MKDIR", configure->programs.mkdir); } if(targets != NULL || includes != NULL) { if(package == NULL) _makefile_output_variable(fp, "MKDIR", configure->programs.mkdir); _makefile_output_variable(fp, "INSTALL", configure->programs.install); } return 0; } static void _variables_binary(Configure * configure, FILE * fp, char * done); static void _variables_library(Configure * configure, FILE * fp, char * done); static void _variables_library_static(Configure * configure, FILE * fp); static void _variables_libtool(Configure * configure, FILE * fp, char * done); static void _variables_script(Configure * configure, FILE * fp, char * done); static void _executables_variables(Configure * configure, FILE * fp, String const * target, char * done) { String const * type; TargetType tt; if((type = config_get(configure->config, target, "type")) == NULL) return; if(done[(tt = enum_string(TT_LAST, sTargetType, type))]) return; switch(tt) { case TT_BINARY: _variables_binary(configure, fp, done); done[TT_OBJECT] = 1; break; case TT_OBJECT: _variables_binary(configure, fp, done); done[TT_BINARY] = 1; break; case TT_LIBRARY: _variables_library(configure, fp, done); done[TT_PLUGIN] = 1; break; case TT_PLUGIN: _variables_library(configure, fp, done); done[TT_LIBRARY] = 1; break; case TT_LIBTOOL: _variables_libtool(configure, fp, done); break; case TT_SCRIPT: _variables_script(configure, fp, done); break; case TT_UNKNOWN: break; } done[tt] = 1; return; } static void _targets_asflags(Configure * configure, FILE * fp); static void _targets_cflags(Configure * configure, FILE * fp); static void _targets_cxxflags(Configure * configure, FILE * fp); static void _targets_exeext(Configure * configure, FILE * fp); static void _targets_ldflags(Configure * configure, FILE * fp); static void _binary_ldflags(Configure * configure, FILE * fp, String const * ldflags); static void _variables_binary(Configure * configure, FILE * fp, char * done) { String * p; if(!done[TT_LIBRARY] && !done[TT_SCRIPT]) { _makefile_output_variable(fp, "OBJDIR", ""); _makefile_output_variable(fp, "PREFIX", configure->prefs->prefix); _makefile_output_variable(fp, "DESTDIR", configure->prefs->destdir); } /* BINDIR */ if(configure->prefs->bindir[0] == '/') _makefile_output_variable(fp, "BINDIR", configure->prefs->bindir); else if((p = string_new_append("$(PREFIX)/", configure->prefs->bindir, NULL)) != NULL) { _makefile_output_variable(fp, "BINDIR", p); string_delete(p); } /* SBINDIR */ if(configure->prefs->sbindir[0] == '/') _makefile_output_variable(fp, "SBINDIR", configure->prefs->sbindir); else if((p = string_new_append("$(PREFIX)/", configure->prefs->sbindir, NULL)) != NULL) { _makefile_output_variable(fp, "SBINDIR", p); string_delete(p); } if(!done[TT_LIBRARY]) { _targets_asflags(configure, fp); _targets_cflags(configure, fp); _targets_cxxflags(configure, fp); _targets_ldflags(configure, fp); _targets_exeext(configure, fp); } } static void _targets_asflags(Configure * configure, FILE * fp) { String const * as; String const * asf; String const * asff; as = config_get(configure->config, NULL, "as"); asff = config_get(configure->config, NULL, "asflags_force"); asf = config_get(configure->config, NULL, "asflags"); if(as != NULL || asff != NULL || asf != NULL) { _makefile_output_variable(fp, "AS", (as != NULL) ? as : configure->programs.as); _makefile_output_variable(fp, "ASFLAGSF", asff); _makefile_output_variable(fp, "ASFLAGS", asf); } } static void _targets_cflags(Configure * configure, FILE * fp) { String const * cc; String const * cff; String const * cf; String const * cppf; String const * cpp; String * p; cppf = config_get(configure->config, NULL, "cppflags_force"); cpp = config_get(configure->config, NULL, "cppflags"); cff = config_get(configure->config, NULL, "cflags_force"); cf = config_get(configure->config, NULL, "cflags"); cc = config_get(configure->config, NULL, "cc"); if(cppf == NULL && cpp == NULL && cff == NULL && cf == NULL && cc == NULL) return; if(cc == NULL) _makefile_output_variable(fp, "CC", configure->programs.cc); else _makefile_output_variable(fp, "CC", cc); _makefile_output_variable(fp, "CPPFLAGSF", cppf); _makefile_output_variable(fp, "CPPFLAGS", cpp); p = NULL; if(configure->os == HO_GNU_LINUX && cff != NULL && string_find(cff, "-ansi")) p = string_new_append(cff, " -D _GNU_SOURCE"); _makefile_output_variable(fp, "CFLAGSF", (p != NULL) ? p : cff); string_delete(p); p = NULL; if(configure->os == HO_GNU_LINUX && cf != NULL && string_find(cf, "-ansi")) p = string_new_append(cf, " -D _GNU_SOURCE"); _makefile_output_variable(fp, "CFLAGS", (p != NULL) ? p : cf); string_delete(p); } static void _targets_cxxflags(Configure * configure, FILE * fp) { String const * cxx; String const * cxxff; String const * cxxf; cxx = config_get(configure->config, NULL, "cxx"); cxxff = config_get(configure->config, NULL, "cxxflags_force"); cxxf = config_get(configure->config, NULL, "cxxflags"); if(cxx != NULL || cxxff != NULL || cxxf != NULL) { if(cxx == NULL) cxx = configure->programs.cxx; _makefile_output_variable(fp, "CXX", cxx); } if(cxxff != NULL) { _makefile_print(fp, "%s%s", "CXXFLAGSF= ", cxxff); if(configure->os == HO_GNU_LINUX && string_find(cxxff, "-ansi")) _makefile_print(fp, "%s", " -D _GNU_SOURCE"); _makefile_print(fp, "%c", '\n'); } if(cxxf != NULL) { _makefile_print(fp, "%s%s", "CXXFLAGS= ", cxxf); if(configure->os == HO_GNU_LINUX && string_find(cxxf, "-ansi")) _makefile_print(fp, "%s", " -D _GNU_SOURCE"); _makefile_print(fp, "%c", '\n'); } } static void _targets_exeext(Configure * configure, FILE * fp) { _makefile_output_variable(fp, "EXEEXT", configure_get_exeext(configure)); } static void _targets_ldflags(Configure * configure, FILE * fp) { String const * p; if((p = config_get(configure->config, NULL, "ldflags_force")) != NULL) { _makefile_print(fp, "%s", "LDFLAGSF="); _binary_ldflags(configure, fp, p); _makefile_print(fp, "%c", '\n'); } if((p = config_get(configure->config, NULL, "ldflags")) != NULL) { _makefile_print(fp, "%s", "LDFLAGS\t="); _binary_ldflags(configure, fp, p); _makefile_print(fp, "%c", '\n'); } } static void _binary_ldflags(Configure * configure, FILE * fp, String const * ldflags) { char const * libs_bsd[] = { "dl", "resolv", "ossaudio", "socket", "ws2_32", NULL }; char const * libs_deforaos[] = { "ossaudio", "resolv", "ssl", "ws2_32", NULL }; char const * libs_gnu[] = { "intl", "ossaudio", "resolv", "socket", "ws2_32", NULL }; char const * libs_macosx[] = { "crypt", "ossaudio", "socket", "ws2_32", NULL }; char const * libs_netbsd[] = { "dl", "resolv", "socket", "ws2_32", NULL }; char const * libs_sunos[] = { "dl", "ossaudio", "ws2_32", NULL }; char const * libs_win32[] = { "dl", "ossaudio", NULL }; char buf[16]; char const ** libs; String * p; String * q; size_t i; if((p = string_new(ldflags)) == NULL) /* XXX report error? */ { _makefile_print(fp, " %s%s", ldflags, "\n"); return; } switch(configure->os) { case HO_DEFORAOS: libs = libs_deforaos; break; case HO_FREEBSD: case HO_OPENBSD: libs = libs_bsd; break; case HO_GNU_LINUX: libs = libs_gnu; break; case HO_MACOSX: libs = libs_macosx; break; case HO_NETBSD: libs = libs_netbsd; break; case HO_SUNOS: libs = libs_sunos; break; case HO_WIN32: libs = libs_win32; break; default: libs = libs_gnu; break; } for(i = 0; libs[i] != NULL; i++) { snprintf(buf, sizeof(buf), "-l %s", libs[i]); if((q = string_find(p, buf)) == NULL) { snprintf(buf, sizeof(buf), "-l%s", libs[i]); q = string_find(p, buf); } if(q == NULL) continue; memmove(q, q + strlen(buf), strlen(q) - strlen(buf) + 1); } _makefile_print(fp, " %s", p); string_delete(p); } static void _variables_library(Configure * configure, FILE * fp, char * done) { String const * libdir; String const * p; if(!done[TT_LIBRARY] && !done[TT_SCRIPT]) { _makefile_output_variable(fp, "OBJDIR", ""); _makefile_output_variable(fp, "PREFIX", configure->prefs->prefix); _makefile_output_variable(fp, "DESTDIR", configure->prefs->destdir); } if((libdir = config_get(configure->config, NULL, "libdir")) == NULL) libdir = configure->prefs->libdir; if(libdir[0] == '/') _makefile_output_variable(fp, "LIBDIR", libdir); else _makefile_print(fp, "%s%s\n", "LIBDIR\t= $(PREFIX)/", libdir); if(!done[TT_BINARY]) { _targets_asflags(configure, fp); _targets_cflags(configure, fp); _targets_cxxflags(configure, fp); _targets_ldflags(configure, fp); _targets_exeext(configure, fp); } if(configure_can_library_static(configure)) _variables_library_static(configure, fp); if((p = config_get(configure->config, NULL, "ld")) == NULL) _makefile_output_variable(fp, "CCSHARED", configure->programs.ccshared); else _makefile_output_variable(fp, "CCSHARED", p); _makefile_output_variable(fp, "SOEXT", configure_get_soext(configure)); } static void _variables_library_static(Configure * configure, FILE * fp) { String const * p; if((p = config_get(configure->config, NULL, "ar")) == NULL) _makefile_output_variable(fp, "AR", configure->programs.ar); else _makefile_output_variable(fp, "AR", p); if((p = config_get(configure->config, NULL, "ranlib")) == NULL) _makefile_output_variable(fp, "RANLIB", configure->programs.ranlib); else _makefile_output_variable(fp, "RANLIB", p); } static void _variables_libtool(Configure * configure, FILE * fp, char * done) { String const * p; _variables_library(configure, fp, done); if(!done[TT_LIBTOOL]) { if((p = config_get(configure->config, NULL, "libtool")) == NULL) _makefile_output_variable(fp, "LIBTOOL", configure->programs.libtool); else _makefile_output_variable(fp, "LIBTOOL", p); } } static void _variables_script(Configure * configure, FILE * fp, char * done) { if(!done[TT_BINARY] && !done[TT_LIBRARY] && !done[TT_SCRIPT]) { _makefile_output_variable(fp, "OBJDIR", ""); _makefile_output_variable(fp, "PREFIX", configure->prefs->prefix); _makefile_output_variable(fp, "DESTDIR", configure->prefs->destdir); } } static int _variables_includes(Configure * configure, FILE * fp) { String const * includes; if((includes = config_get(configure->config, NULL, "includes")) == NULL) return 0; if(fp == NULL) return 0; if(configure->prefs->includedir[0] == '/') _makefile_output_variable(fp, "INCLUDEDIR", configure->prefs->includedir); else _makefile_print(fp, "%s%s\n", "INCLUDEDIR= $(PREFIX)/", configure->prefs->includedir); return 0; } static int _variables_subdirs(Configure * configure, FILE * fp) { Config * config = configure->config; String const * sections[] = { "dist" }; size_t i; String * p; String const * q; if(config_get(config, NULL, "subdirs") == NULL || config_get(config, NULL, "package") != NULL || config_get(config, NULL, "targets") != NULL || config_get(config, NULL, "includes") != NULL) return 0; for(i = 0; i < sizeof(sections) / sizeof(*sections); i++) { if((q = config_get(config, NULL, sections[i])) == NULL) continue; if((p = strdup(q)) == NULL) return -1; for(q = strtok(p, ","); q != NULL; q = strtok(NULL, ",")) if(config_get(config, q, "install") != NULL) break; free(p); if(q != NULL) return 0; } return _makefile_output_variable(fp, "MKDIR", configure->programs.mkdir); } static int _targets_all(Configure * configure, FILE * fp); static int _targets_subdirs(Configure * configure, FILE * fp); static int _targets_target(Configure * configure, FILE * fp, String const * target); static int _write_targets(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * targets; String * q; size_t i; char c; if(_targets_all(configure, fp) != 0 || _targets_subdirs(configure, fp) != 0) return 1; if((p = config_get(configure->config, NULL, "targets")) == NULL) return 0; if((targets = string_new(p)) == NULL) return 1; q = targets; for(i = 0;; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; ret |= _targets_target(configure, fp, targets); if(c == '\0') break; targets += i + 1; i = 0; } string_delete(q); return ret; } static int _targets_all(Configure * configure, FILE * fp) { char const * depends[] = { NULL, NULL }; size_t i = 0; if(config_get(configure->config, NULL, "subdirs") != NULL) depends[i++] = "subdirs"; if(config_get(configure->config, NULL, "targets") != NULL) depends[i++] = "$(TARGETS)"; _makefile_target(fp, "all", depends[0], depends[1], NULL); return 0; } static int _targets_subdirs(Configure * configure, FILE * fp) { String const * subdirs; if((subdirs = config_get(configure->config, NULL, "subdirs")) != NULL) { _makefile_target(fp, "subdirs", NULL); _makefile_subdirs(fp, NULL); } return 0; } static int _target_objs(Configure * configure, FILE * fp, String const * target); static int _target_binary(Configure * configure, FILE * fp, String const * target); static int _target_library(Configure * configure, FILE * fp, String const * target); static int _target_library_static(Configure * configure, FILE * fp, String const * target); static int _target_libtool(Configure * configure, FILE * fp, String const * target); static int _target_object(Configure * configure, FILE * fp, String const * target); static int _target_plugin(Configure * configure, FILE * fp, String const * target); static int _target_script(Configure * configure, FILE * fp, String const * target); static int _targets_target(Configure * configure, FILE * fp, String const * target) { String const * type; TargetType tt; if((type = config_get(configure->config, target, "type")) == NULL) { fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": no type defined for target\n"); return 1; } tt = enum_string(TT_LAST, sTargetType, type); switch(tt) { case TT_BINARY: return _target_binary(configure, fp, target); case TT_LIBRARY: return _target_library(configure, fp, target); case TT_LIBTOOL: return _target_libtool(configure, fp, target); case TT_OBJECT: return _target_object(configure, fp, target); case TT_PLUGIN: return _target_plugin(configure, fp, target); case TT_SCRIPT: return _target_script(configure, fp, target); case TT_UNKNOWN: fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": unknown type for target\n"); return 1; } return 0; } static int _objs_source(FILE * fp, String * source, TargetType tt); static int _target_objs(Configure * configure, FILE * fp, String const * target) { int ret = 0; String const * p; TargetType tt = TT_UNKNOWN; String * sources; String * q; size_t i; char c; if((p = config_get(configure->config, target, "type")) != NULL) tt = enum_string(TT_LAST, sTargetType, p); if((p = config_get(configure->config, target, "sources")) == NULL) /* a binary target may have no sources */ return 0; if((sources = string_new(p)) == NULL) return 1; q = sources; _makefile_print(fp, "%s%s%s", "\n", target, "_OBJS ="); for(i = 0; ret == 0; i++) { if(sources[i] != ',' && sources[i] != '\0') continue; c = sources[i]; sources[i] = '\0'; ret = _objs_source(fp, sources, tt); if(c == '\0') break; sources += i + 1; i = 0; } _makefile_print(fp, "%c", '\n'); string_delete(q); return ret; } static int _objs_source(FILE * fp, String * source, TargetType tt) { int ret = 0; String const * extension; size_t len; if((extension = _source_extension(source)) == NULL) { fprintf(stderr, "%s%s%s", PROGNAME ": ", source, ": no extension for source\n"); return 1; } len = string_length(source) - string_length(extension) - 1; source[len] = '\0'; switch(_source_type(extension)) { case OT_ASM_SOURCE: case OT_C_SOURCE: case OT_CXX_SOURCE: case OT_OBJC_SOURCE: case OT_OBJCXX_SOURCE: _makefile_print(fp, "%s%s%s", " $(OBJDIR)", source, (tt == TT_LIBTOOL) ? ".lo" : ".o"); break; case OT_UNKNOWN: ret = 1; fprintf(stderr, "%s%s%s", PROGNAME ": ", source, ": unknown extension for source\n"); break; } source[len] = '.'; return ret; } static int _target_flags(Configure * configure, FILE * fp, String const * target); static int _target_binary(Configure * configure, FILE * fp, String const * target) { String const * p; if(_target_objs(configure, fp, target) != 0) return 1; if(_target_flags(configure, fp, target) != 0) return 1; _makefile_print(fp, "%c", '\n'); /* output the binary target */ _makefile_print(fp, "%s%s%s%s%s%s", "$(OBJDIR)", target, "$(EXEEXT)", ": $(", target, "_OBJS)"); if((p = config_get(configure->config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); _makefile_print(fp, "%c", '\n'); /* build the binary */ _makefile_print(fp, "%s%s%s%s%s%s%s", "\t$(CC) -o $(OBJDIR)", target, "$(EXEEXT) $(", target, "_OBJS) $(", target, "_LDFLAGS)\n"); return 0; } static void _flags_asm(Configure * configure, FILE * fp, String const * target); static void _flags_c(Configure * configure, FILE * fp, String const * target); static void _flags_cxx(Configure * configure, FILE * fp, String const * target); static int _target_flags(Configure * configure, FILE * fp, String const * target) { char done[OT_COUNT]; String const * p; String * sources; String * q; String const * extension; ObjectType type; char c; size_t i; memset(&done, 0, sizeof(done)); if((p = config_get(configure->config, target, "sources")) == NULL || string_length(p) == 0) { if((p = config_get(configure->config, target, "type")) != NULL && string_compare(p, "binary") == 0) _flags_c(configure, fp, target); return 0; } if((sources = string_new(p)) == NULL) return 1; q = sources; for(i = 0;; i++) { if(sources[i] != ',' && sources[i] != '\0') continue; c = sources[i]; sources[i] = '\0'; extension = _source_extension(sources); if(extension == NULL) { sources[i] = c; continue; } type = _source_type(extension); if(!done[type]) switch(type) { case OT_ASM_SOURCE: _flags_asm(configure, fp, target); break; case OT_OBJC_SOURCE: done[OT_C_SOURCE] = 1; /* fallback */ case OT_C_SOURCE: done[OT_OBJC_SOURCE] = 1; _flags_c(configure, fp, target); break; case OT_OBJCXX_SOURCE: done[OT_CXX_SOURCE] = 1; /* fallback */ case OT_CXX_SOURCE: done[OT_OBJCXX_SOURCE] = 1; _flags_cxx(configure, fp, target); break; case OT_UNKNOWN: break; } done[type] = 1; if(c == '\0') break; sources += i + 1; i = 0; } string_delete(q); return 0; } static void _flags_asm(Configure * configure, FILE * fp, String const * target) { String const * p; _makefile_print(fp, "%s%s", target, "_ASFLAGS = $(CPPFLAGSF)" " $(CPPFLAGS) $(ASFLAGSF) $(ASFLAGS)"); if((p = config_get(configure->config, target, "asflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%c", '\n'); } static void _flags_c(Configure * configure, FILE * fp, String const * target) { String const * p; _makefile_print(fp, "%s%s", target, "_CFLAGS = $(CPPFLAGSF)" " $(CPPFLAGS)"); if((p = config_get(configure->config, target, "cppflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%s", " $(CFLAGSF) $(CFLAGS)"); if((p = config_get(configure->config, target, "cflags")) != NULL) { _makefile_print(fp, " %s", p); if(configure->os == HO_GNU_LINUX && string_find(p, "-ansi")) _makefile_print(fp, "%s", " -D _GNU_SOURCE"); } _makefile_print(fp, "\n%s%s", target, "_LDFLAGS = $(LDFLAGSF) $(LDFLAGS)"); if((p = config_get(configure->config, target, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); _makefile_print(fp, "%c", '\n'); } static void _flags_cxx(Configure * configure, FILE * fp, String const * target) { String const * p; _makefile_print(fp, "%s%s", target, "_CXXFLAGS = $(CPPFLAGSF)" " $(CPPFLAGS) $(CXXFLAGSF) $(CXXFLAGS)"); if((p = config_get(configure->config, target, "cxxflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "\n%s%s", target, "_LDFLAGS = $(LDFLAGSF) $(LDFLAGS)"); if((p = config_get(configure->config, target, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); _makefile_print(fp, "%c", '\n'); } static int _target_library(Configure * configure, FILE * fp, String const * target) { String const * p; String * q; String * soname; if(_target_objs(configure, fp, target) != 0) return 1; if(_target_flags(configure, fp, target) != 0) return 1; if(configure_can_library_static(configure) /* generate a static library */ && _target_library_static(configure, fp, target) != 0) return 1; if((p = config_get(configure->config, target, "soname")) != NULL) soname = string_new(p); else if(configure->os == HO_MACOSX) /* versioning is different on MacOS X */ soname = string_new_append(target, ".0.0$(SOEXT)", NULL); else if(configure->os == HO_WIN32) /* and on Windows */ soname = string_new_append(target, "$(SOEXT)", NULL); else soname = string_new_append(target, "$(SOEXT)", ".0", NULL); if(soname == NULL) return 1; if(configure->os == HO_MACOSX) _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", soname, ": $(", target, "_OBJS)"); else if(configure->os == HO_WIN32) _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", soname, ": $(", target, "_OBJS)"); else _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", soname, ".0: $(", target, "_OBJS)"); if((p = config_get(configure->config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); _makefile_print(fp, "%c", '\n'); /* build the shared library */ _makefile_print(fp, "%s%s%s", "\t$(CCSHARED) -o $(OBJDIR)", soname, (configure->os != HO_MACOSX && configure->os != HO_WIN32) ? ".0" : ""); if((p = config_get(configure->config, target, "install")) != NULL) { /* soname is not available on MacOS X */ if(configure->os == HO_MACOSX) _makefile_print(fp, "%s%s%s%s%s", " -install_name ", p, "/", target, ".0$(SOEXT)"); else if(configure->os != HO_WIN32) _makefile_print(fp, "%s%s", " -Wl,-soname,", soname); } _makefile_print(fp, "%s%s%s%s%s", " $(", target, "_OBJS) $(", target, "_LDFLAGS)"); if((q = string_new_append(target, "$(SOEXT)", NULL)) == NULL) { string_delete(soname); return 1; } if((p = config_get(configure->config, q, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); string_delete(q); _makefile_print(fp, "%c", '\n'); if(configure->os == HO_MACOSX) { _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, ".0$(SOEXT): $(OBJDIR)", soname, "\n"); _makefile_print(fp, "%s%s%s%s%s%s", "\t$(LN) -s -- ", soname, " $(OBJDIR)", target, ".0$(SOEXT)", "\n"); _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, "$(SOEXT): $(OBJDIR)", soname, "\n"); _makefile_print(fp, "%s%s%s%s%s", "\t$(LN) -s -- ", soname, " $(OBJDIR)", target, "$(SOEXT)\n"); } else if(configure->os != HO_WIN32) { _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", soname, ": $(OBJDIR)", soname, ".0\n"); _makefile_print(fp, "%s%s%s%s%s", "\t$(LN) -s -- ", soname, ".0 $(OBJDIR)", soname, "\n"); _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, "$(SOEXT): $(OBJDIR)", soname, ".0\n"); _makefile_print(fp, "%s%s%s%s%s", "\t$(LN) -s -- ", soname, ".0 $(OBJDIR)", target, "$(SOEXT)\n"); } string_delete(soname); return 0; } static int _target_library_static(Configure * configure, FILE * fp, String const * target) { String const * p; String * q; size_t len; _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, ".a: $(", target, "_OBJS)"); if((p = config_get(configure->config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); _makefile_print(fp, "%c", '\n'); /* build the static library */ _makefile_print(fp, "%s%s%s%s%s", "\t$(AR) -rc $(OBJDIR)", target, ".a $(", target, "_OBJS)"); len = strlen(target) + 3; if((q = malloc(len)) == NULL) return 1; snprintf(q, len, "%s.a", target); if((p = config_get(configure->config, q, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); free(q); _makefile_print(fp, "%s%s%s", "\n\t$(RANLIB) $(OBJDIR)", target, ".a\n"); return 0; } static int _target_libtool(Configure * configure, FILE * fp, String const * target) { String const * p; if(_target_objs(configure, fp, target) != 0) return 1; if(_target_flags(configure, fp, target) != 0) return 1; _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, ".la: $(", target, "_OBJS)\n"); _makefile_print(fp, "%s%s%s%s%s", "\t$(LIBTOOL) --mode=link $(CC) -o $(OBJDIR)", target, ".la $(", target, "_OBJS)"); if((p = config_get(configure->config, target, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); _makefile_print(fp, "%s%s%s", " -rpath $(LIBDIR) $(", target, "_LDFLAGS)\n"); return 0; } static int _target_object(Configure * configure, FILE * fp, String const * target) { String const * p; String const * extension; if((p = config_get(configure->config, target, "sources")) == NULL) { fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": No sources for target\n"); return 1; } if(strchr(p, ',') != NULL) { fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": An object can have only one source file\n"); return 1; } if((extension = _source_extension(p)) == NULL) return 1; switch(_source_type(extension)) { case OT_ASM_SOURCE: _makefile_print(fp, "\n%s%s%s%s\n%s%s", target, "_OBJS = ", "$(OBJDIR)", target, target, "_ASFLAGS =" " $(CPPFLAGSF) $(CPPFLAGS) $(ASFLAGSF)" " $(ASFLAGS)"); if((p = config_get(configure->config, target, "asflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%c", '\n'); break; case OT_C_SOURCE: case OT_OBJC_SOURCE: _makefile_print(fp, "\n%s%s%s%s\n%s%s", target, "_OBJS = ", "$(OBJDIR)", target, target, "_CFLAGS =" " $(CPPFLAGSF) $(CPPFLAGS) $(CFLAGSF)" " $(CFLAGS)"); if((p = config_get(configure->config, target, "cflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%c", '\n'); break; case OT_CXX_SOURCE: case OT_OBJCXX_SOURCE: _makefile_print(fp, "\n%s%s%s%s\n%s%s", target, "_OBJS = ", "$(OBJDIR)", target, target, "_CXXFLAGS =" " $(CPPFLAGSF) $(CPPFLAGS)" " $(CXXFLAGS)"); if((p = config_get(configure->config, target, "cxxflags")) != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%c", '\n'); break; case OT_UNKNOWN: fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": Unknown source type for object\n"); return 1; } return 0; } static int _target_plugin(Configure * configure, FILE * fp, String const * target) { String const * p; String * q; if(_target_objs(configure, fp, target) != 0) return 1; if(_target_flags(configure, fp, target) != 0) return 1; _makefile_print(fp, "%s%s%s%s%s", "\n$(OBJDIR)", target, "$(SOEXT): $(", target, "_OBJS)"); if((p = config_get(configure->config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); _makefile_print(fp, "%c", '\n'); /* build the plug-in */ _makefile_print(fp, "%s%s%s%s%s%s%s", "\t$(CCSHARED) -o $(OBJDIR)", target, "$(SOEXT) $(", target, "_OBJS) $(", target, "_LDFLAGS)"); if((q = string_new_append(target, "$(SOEXT)", NULL)) == NULL) return error_print(PROGNAME); if((p = config_get(configure->config, q, "ldflags")) != NULL) _binary_ldflags(configure, fp, p); string_delete(q); _makefile_print(fp, "%c", '\n'); return 0; } static int _objects_target(Configure * configure, FILE * fp, String const * target); static int _write_objects(Configure * configure, FILE * fp) { String const * p; String * targets; String * q; char c; size_t i; int ret = 0; if((p = config_get(configure->config, NULL, "targets")) == NULL) return 0; if((targets = string_new(p)) == NULL) return 1; q = targets; for(i = 0;; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; ret += _objects_target(configure, fp, targets); if(c == '\0') break; targets += i + 1; i = 0; } string_delete(q); return ret; } static void _script_check(Configure * configure, String const * target, String const * script); static int _script_depends(Configure * configure, FILE * fp, String const * target); static String * _script_path(Configure * configure, String const * script); static void _script_security(Configure * configure, String const * target, String const * script); static int _target_script(Configure * configure, FILE * fp, String const * target) { String const * prefix; String const * script; int phony; if((script = config_get(configure->config, target, "script")) == NULL) { fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": No script for target\n"); return 1; } if(fp == NULL) _script_check(configure, target, script); if(configure->prefs->flags & PREFS_S) _script_security(configure, target, script); phony = _makefile_is_phony(configure, target); _makefile_print(fp, "\n%s%s:", phony ? "" : "$(OBJDIR)", target); _script_depends(configure, fp, target); if((prefix = config_get(configure->config, target, "prefix")) == NULL) prefix = "$(PREFIX)"; _makefile_print(fp, "\n\t%s -P \"%s\" -- \"%s%s\"\n", script, prefix, phony ? "" : "$(OBJDIR)", target); return 0; } static void _script_check(Configure * configure, String const * target, String const * script) { String * path; if((path = _script_path(configure, script)) == NULL) { error_print(PROGNAME); return; } /* XXX make it clear these are warnings */ if(access(path, R_OK) != 0) error_set_print(PROGNAME, 0, "%s: %s%s%s%s%s", target, "The \"", path, "\" script is not readable (", strerror(errno), ")"); else if(access(path, R_OK | X_OK) != 0) error_set_print(PROGNAME, 0, "%s: %s%s%s%s%s", target, "The \"", path, "\" script is not executable (", strerror(errno), ")"); string_delete(path); } static int _script_depends(Configure * configure, FILE * fp, String const * target) { Config * config = configure->config; String const * p; if((p = config_get(config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); return 0; } static String * _script_path(Configure * configure, String const * script) { String * ret; String const * directory; ssize_t i; String * p = NULL; if((directory = config_get(configure->config, NULL, "directory")) == NULL) { error_print(PROGNAME); return NULL; } /* XXX truncate scripts at the first space (to allow arguments) */ if((i = string_index(script, " ")) > 0) { if((p = string_new_length(script, i)) == NULL) { error_print(PROGNAME); return NULL; } script = p; } if(script[0] == '/') ret = string_new(script); else if(string_compare_length(script, "./", 2) == 0) ret = string_new_append(directory, &script[1], NULL); else ret = string_new_append(directory, "/", script, NULL); string_delete(p); return ret; } static void _script_security(Configure * configure, String const * target, String const * script) { String * path; if((path = _script_path(configure, script)) == NULL) { error_print(PROGNAME); return; } error_set_print(PROGNAME, 0, "%s: %s%s%s", target, "The \"", path, "\" script is executed while compiling"); string_delete(path); } static int _target_source(Configure * configure, FILE * fp, String const * target, String * source); static int _objects_target(Configure * configure, FILE * fp, String const * target) { int ret = 0; String const * p; String * sources; String * q; size_t i; char c; if((p = config_get(configure->config, target, "sources")) == NULL) return 0; if((sources = string_new(p)) == NULL) return 1; q = sources; for(i = 0;; i++) { if(sources[i] != ',' && sources[i] != '\0') continue; c = sources[i]; sources[i] = '\0'; ret |= _target_source(configure, fp, target, sources); if(c == '\0') break; sources += i + 1; i = 0; } string_delete(q); return ret; } static int _source_depends(Configure * configure, FILE * fp, String const * source); static int _source_subdir(FILE * fp, String * source); static int _target_source(Configure * configure, FILE * fp, String const * target, String * source) /* FIXME check calls to _source_depends() */ { int ret = 0; String const * extension; TargetType tt = TT_UNKNOWN; ObjectType ot; size_t len; String const * p; String const * q; if((p = config_get(configure->config, target, "type")) != NULL) tt = enum_string(TT_LAST, sTargetType, p); if((extension = _source_extension(source)) == NULL) return 1; len = string_length(source) - string_length(extension) - 1; source[len] = '\0'; switch((ot = _source_type(extension))) { case OT_ASM_SOURCE: if(tt == TT_OBJECT) _makefile_print(fp, "%s%s", "\n$(OBJDIR)", target); else _makefile_print(fp, "%s%s%s", "\n$(OBJDIR)", source, ".o"); if(tt == TT_LIBTOOL) _makefile_print(fp, " %s.lo", source); _makefile_print(fp, "%s%s%s%s", ": ", source, ".", extension); source[len] = '.'; /* FIXME ugly */ _source_depends(configure, fp, source); source[len] = '\0'; _makefile_print(fp, "%s", "\n\t"); if(strchr(source, '/') != NULL) ret = _source_subdir(fp, source); if(tt == TT_LIBTOOL) _makefile_print(fp, "%s", "$(LIBTOOL) --mode=compile "); _makefile_print(fp, "%s%s%s", "$(AS) $(", target, "_ASFLAGS)"); if(tt == TT_OBJECT) _makefile_print(fp, "%s%s%s%s%s%s", " -o $(OBJDIR)", target, " ", source, ".", extension); else _makefile_print(fp, "%s%s%s%s%s%s", " -o $(OBJDIR)", source, ".o ", source, ".", extension); _makefile_print(fp, "%c", '\n'); break; case OT_C_SOURCE: case OT_OBJC_SOURCE: if(tt == TT_OBJECT) _makefile_print(fp, "%s%s", "\n$(OBJDIR)", target); else _makefile_print(fp, "%s%s%s", "\n$(OBJDIR)", source, ".o"); if(tt == TT_LIBTOOL) _makefile_print(fp, " %s%s", source, ".lo"); _makefile_print(fp, "%s%s%s%s", ": ", source, ".", extension); source[len] = '.'; /* FIXME ugly */ _source_depends(configure, fp, source); _makefile_print(fp, "%s", "\n\t"); if(strchr(source, '/') != NULL) ret = _source_subdir(fp, source); /* FIXME do both wherever also relevant */ p = config_get(configure->config, source, "cppflags"); q = config_get(configure->config, source, "cflags"); source[len] = '\0'; if(tt == TT_LIBTOOL) _makefile_print(fp, "%s", "$(LIBTOOL) --mode=compile "); _makefile_print(fp, "%s", "$(CC)"); if(p != NULL) _makefile_print(fp, " %s", p); _makefile_print(fp, "%s%s%s", " $(", target, "_CFLAGS)"); if(q != NULL) { _makefile_print(fp, " %s", q); if(configure->os == HO_GNU_LINUX && string_find(q, "-ansi")) _makefile_print(fp, "%s", " -D _GNU_SOURCE"); } if(tt == TT_OBJECT) _makefile_print(fp, "%s%s", " -o $(OBJDIR)", target); else _makefile_print(fp, "%s%s%s", " -o $(OBJDIR)", source, ".o"); _makefile_print(fp, "%s%s%s%s%c", " -c ", source, ".", extension, '\n'); break; case OT_CXX_SOURCE: case OT_OBJCXX_SOURCE: if(tt == TT_OBJECT) _makefile_print(fp, "%s%s", "\n$(OBJDIR)", target); else _makefile_print(fp, "%s%s%s", "\n$(OBJDIR)", source, ".o"); _makefile_print(fp, "%s%s%s%s", ": ", source, ".", extension); source[len] = '.'; /* FIXME ugly */ _source_depends(configure, fp, source); p = config_get(configure->config, source, "cxxflags"); source[len] = '\0'; _makefile_print(fp, "%s", "\n\t"); if(strchr(source, '/') != NULL) ret = _source_subdir(fp, source); _makefile_print(fp, "%s%s%s", "$(CXX) $(", target, "_CXXFLAGS)"); if(p != NULL) _makefile_print(fp, " %s", p); if(tt == TT_OBJECT) _makefile_print(fp, "%s%s", " -o $(OBJDIR)", target); else _makefile_print(fp, "%s%s%s", " -o $(OBJDIR)", source, ".o"); _makefile_print(fp, "%s%s%s%s\n", " -c ", source, ".", extension); break; case OT_UNKNOWN: fprintf(stderr, "%s%s%s", PROGNAME ": ", target, ": Unknown source type for object\n"); ret = 1; break; } source[len] = '.'; return ret; } static int _source_depends(Configure * configure, FILE * fp, String const * target) { Config * config = configure->config; String const * p; if((p = config_get(config, target, "depends")) != NULL && _makefile_expand(fp, p) != 0) return error_print(PROGNAME); return 0; } static int _source_subdir(FILE * fp, String * source) { char * p; char const * q; if((p = strdup(source)) == NULL) return 1; q = dirname(p); _makefile_print(fp, "@[ -d \"%s%s\" ] || $(MKDIR) -- \"%s%s\"\n\t", "$(OBJDIR)", q, "$(OBJDIR)", q); free(p); return 0; } static int _clean_targets(Configure * configure, FILE * fp); static int _write_clean(Configure * configure, FILE * fp) { _makefile_target(fp, "clean", NULL); if(config_get(configure->config, NULL, "subdirs") != NULL) _makefile_subdirs(fp, "clean"); return _clean_targets(configure, fp); } static int _clean_targets(Configure * configure, FILE * fp) { Config * config = configure->config; String const * prefix; String const * p; String * targets; String * q; size_t i; char c; if((p = config_get(config, NULL, "targets")) == NULL) return 0; if((targets = string_new(p)) == NULL) return 1; q = targets; /* remove all of the object files */ _makefile_print(fp, "%s", "\t$(RM) --"); for(i = 0;; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; _makefile_print(fp, "%s%s%s", " $(", targets, "_OBJS)"); if(c == '\0') break; targets[i] = c; targets += i + 1; i = 0; } _makefile_print(fp, "%c", '\n'); targets = q; /* let each scripted target remove the relevant object files */ for(i = 0;; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; if((p = config_get(config, targets, "type")) != NULL && strcmp(p, "script") == 0 && (p = config_get(config, targets, "script")) != NULL) { if((prefix = config_get(config, targets, "prefix")) == NULL) prefix = "$(PREFIX)"; _makefile_print(fp, "\t%s%s%s%s%s%s\n", p, " -c -P \"", prefix, "\" -- \"$(OBJDIR)", targets, "\""); } if(c == '\0') break; targets[i] = c; targets += i + 1; i = 0; } string_delete(q); return 0; } static int _write_distclean(Configure * configure, FILE * fp) { String const * subdirs; /* only depend on the "clean" target if we do not have subfolders */ if((subdirs = config_get(configure->config, NULL, "subdirs")) == NULL) _makefile_target(fp, "distclean", "clean", NULL); else { _makefile_target(fp, "distclean", NULL); _makefile_subdirs(fp, "distclean"); _clean_targets(configure, fp); } /* FIXME do not erase targets that need be distributed */ if(config_get(configure->config, NULL, "targets") != NULL) _makefile_remove(fp, 0, "$(TARGETS)", NULL); return 0; } static int _dist_subdir(Configure * configure, FILE * fp, Config * subdir); static int _write_dist(Configure * configure, FILE * fp, configArray * ca, int from, int to) { String const * package; String const * version; Config * p; int i; package = config_get(configure->config, NULL, "package"); version = config_get(configure->config, NULL, "version"); if(package == NULL || version == NULL) return 0; _makefile_target(fp, "dist", NULL); _makefile_remove(fp, 1, "$(OBJDIR)$(PACKAGE)-$(VERSION)", NULL); _makefile_link(fp, 1, "\"$$PWD\"", "$(OBJDIR)$(PACKAGE)-$(VERSION)"); _makefile_print(fp, "%s", "\t@cd $(OBJDIR). && $(TAR) -czvf" " $(PACKAGE)-$(VERSION).tar.gz -- \\\n"); for(i = from + 1; i < to; i++) { array_get_copy(ca, i, &p); _dist_subdir(configure, fp, p); } if(from < to) { array_get_copy(ca, from, &p); _dist_subdir(configure, fp, p); } else return 1; _makefile_remove(fp, 0, "$(OBJDIR)$(PACKAGE)-$(VERSION)", NULL); return 0; } static int _write_distcheck(Configure * configure, FILE * fp) { String const * package; String const * version; const char pretarget[] = "\ndistcheck: dist\n" "\t$(TAR) -xzvf $(OBJDIR)$(PACKAGE)-$(VERSION).tar.gz\n" "\t$(MKDIR) -- $(PACKAGE)-$(VERSION)/objdir\n" "\t$(MKDIR) -- $(PACKAGE)-$(VERSION)/destdir\n"; const char target[] = "\tcd \"$(PACKAGE)-$(VERSION)\" && $(MAKE) OBJDIR=\"$$PWD/objdir/\"\n" "\tcd \"$(PACKAGE)-$(VERSION)\" && $(MAKE) OBJDIR=\"$$PWD/objdir/\" DESTDIR=\"$$PWD/destdir\" install\n" "\tcd \"$(PACKAGE)-$(VERSION)\" && $(MAKE) OBJDIR=\"$$PWD/objdir/\" DESTDIR=\"$$PWD/destdir\" uninstall\n" "\tcd \"$(PACKAGE)-$(VERSION)\" && $(MAKE) OBJDIR=\"$$PWD/objdir/\" distclean\n" "\tcd \"$(PACKAGE)-$(VERSION)\" && $(MAKE) dist\n"; const char posttarget[] = "\t$(RM) -r -- $(PACKAGE)-$(VERSION)\n"; package = config_get(configure->config, NULL, "package"); version = config_get(configure->config, NULL, "version"); if(package == NULL || version == NULL) return 0; _makefile_print(fp, "%s%s%s", pretarget, target, posttarget); return 0; } static int _dist_subdir_dist(FILE * fp, String const * path, String const * dist); static int _dist_subdir(Configure * configure, FILE * fp, Config * subdir) { Config * config = configure->config; String const * path; size_t len; String const * p; String * targets; String * q; String const * includes; String const * dist; size_t i; char c; String const * quote; path = config_get(config, NULL, "directory"); len = string_length(path); path = config_get(subdir, NULL, "directory"); path = &path[len]; if(path[0] == '/') path++; if((p = config_get(subdir, NULL, "targets")) != NULL) { /* FIXME unique SOURCES */ if((targets = string_new(p)) == NULL) return 1; q = targets; for(i = 0;; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; if((dist = config_get(subdir, targets, "sources")) != NULL) _dist_subdir_dist(fp, path, dist); if(c == '\0') break; targets += i + 1; i = 0; } string_delete(q); } if((includes = config_get(subdir, NULL, "includes")) != NULL) _dist_subdir_dist(fp, path, includes); if((dist = config_get(subdir, NULL, "dist")) != NULL) _dist_subdir_dist(fp, path, dist); quote = (strchr(path, ' ') != NULL) ? "\"" : ""; _makefile_print(fp, "%s%s%s%s%s%s%s%s", "\t\t", quote, "$(PACKAGE)-$(VERSION)/", path, (path[0] == '\0') ? "" : "/", PROJECT_CONF, quote, (path[0] == '\0') ? "\n" : " \\\n"); return 0; } static int _dist_subdir_dist(FILE * fp, String const * path, String const * dist) { String * d; String * p; size_t i; char c; String const * quote; if((d = string_new(dist)) == NULL) return 1; p = d; for(i = 0;; i++) { if(d[i] != ',' && d[i] != '\0') continue; c = d[i]; d[i] = '\0'; quote = (strchr(path, ' ') != NULL || strchr(d, ' ') != NULL) ? "\"" : ""; _makefile_print(fp, "%s%s%s%s%s%s%s%s", "\t\t", quote, "$(PACKAGE)-$(VERSION)/", (path[0] == '\0') ? "" : path, (path[0] == '\0') ? "" : "/", d, quote, " \\\n"); if(c == '\0') break; d[i] = c; d += i + 1; i = 0; } string_delete(p); return 0; } static int _install_targets(Configure * configure, FILE * fp); static int _install_includes(Configure * configure, FILE * fp); static int _install_dist(Configure * configure, FILE * fp); static int _write_install(Configure * configure, FILE * fp) { int ret = 0; char const * targets; targets = config_get(configure->config, NULL, "targets"); _makefile_target(fp, "install", (targets != NULL) ? "$(TARGETS)" : NULL, NULL); if(config_get(configure->config, NULL, "subdirs") != NULL) _makefile_subdirs(fp, "install"); ret |= _install_targets(configure, fp); ret |= _install_includes(configure, fp); ret |= _install_dist(configure, fp); return ret; } static int _install_target(Configure * configure, FILE * fp, String const * target); static int _install_targets(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * q; String * targets; size_t i; char c; if((p = config_get(configure->config, NULL, "targets")) == NULL) return 0; if((targets = string_new(p)) == NULL) return 1; q = targets; for(i = 0; ret == 0; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; ret |= _install_target(configure, fp, targets); if(c == '\0') break; targets += i + 1; i = 0; } string_delete(q); return ret; } static void _install_target_binary(Configure * configure, FILE * fp, String const * target); static int _install_target_library(Configure * configure, FILE * fp, String const * target); static void _install_target_libtool(Configure * configure, FILE * fp, String const * target); static void _install_target_object(Configure * configure, FILE * fp, String const * target); static void _install_target_plugin(Configure * configure, FILE * fp, String const * target); static void _install_target_script(Configure * configure, FILE * fp, String const * target); static int _install_target(Configure * configure, FILE * fp, String const * target) { int ret = 0; String const * type; TargetType tt; if((type = config_get(configure->config, target, "type")) == NULL) return 1; switch((tt = enum_string(TT_LAST, sTargetType, type))) { case TT_BINARY: _install_target_binary(configure, fp, target); break; case TT_LIBRARY: ret = _install_target_library(configure, fp, target); break; case TT_LIBTOOL: _install_target_libtool(configure, fp, target); break; case TT_OBJECT: _install_target_object(configure, fp, target); break; case TT_PLUGIN: _install_target_plugin(configure, fp, target); break; case TT_SCRIPT: _install_target_script(configure, fp, target); break; case TT_UNKNOWN: break; } return ret; } static void _install_target_binary(Configure * configure, FILE * fp, String const * target) { String const * path; if((path = config_get(configure->config, target, "install")) == NULL) return; _makefile_mkdir(fp, path); _makefile_print(fp, "%s%s%s%s/%s%s\n", "\t$(INSTALL) -m 0755 $(OBJDIR)", target, "$(EXEEXT) $(DESTDIR)", path, target, "$(EXEEXT)"); } static int _install_target_library(Configure * configure, FILE * fp, String const * target) { String const * path; String const * p; String * soname; if((path = config_get(configure->config, target, "install")) == NULL) return 0; _makefile_mkdir(fp, path); if(configure_can_library_static(configure)) /* install the static library */ _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(INSTALL) -m 0644 $(OBJDIR)", target, ".a $(DESTDIR)", path, target, ".a\n"); if((p = config_get(configure->config, target, "soname")) != NULL) soname = string_new(p); else if(configure->os == HO_MACOSX) /* versioning is different on MacOS X */ soname = string_new_append(target, ".0.0$(SOEXT)", NULL); else if(configure->os == HO_WIN32) /* and on Windows */ soname = string_new_append(target, "$(SOEXT)", NULL); else soname = string_new_append(target, "$(SOEXT)", ".0", NULL); if(soname == NULL) return 1; /* install the shared library */ if(configure->os == HO_MACOSX) { _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(INSTALL) -m 0755 $(OBJDIR)", soname, " $(DESTDIR)", path, soname, "\n"); _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(LN) -s -- ", soname, " $(DESTDIR)", path, target, ".0$(SOEXT)\n"); _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(LN) -s -- ", soname, " $(DESTDIR)", path, target, "$(SOEXT)\n"); } else if(configure->os == HO_WIN32) _makefile_print(fp, "%s%s%s%s%s%s%s", "\t$(INSTALL) -m 0755 $(OBJDIR)", soname, " $(DESTDIR)", path, "/", soname, "\n"); else { _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(INSTALL) -m 0755 $(OBJDIR)", soname, ".0 $(DESTDIR)", path, soname, ".0\n"); _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(LN) -s -- ", soname, ".0 $(DESTDIR)", path, soname, "\n"); _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(LN) -s -- ", soname, ".0 $(DESTDIR)", path, target, "$(SOEXT)\n"); } string_delete(soname); return 0; } static void _install_target_libtool(Configure * configure, FILE * fp, String const * target) { String const * path; if((path = config_get(configure->config, target, "install")) == NULL) return; _makefile_mkdir(fp, path); _makefile_print(fp, "%s%s%s%s/%s%s", "\t$(LIBTOOL) --mode=install $(INSTALL)" " -m 0755 $(OBJDIR)", target, ".la $(DESTDIR)", path, target, ".la\n"); _makefile_print(fp, "%s/%s\n", "\t$(LIBTOOL) --mode=finish $(DESTDIR)", path); } static void _install_target_object(Configure * configure, FILE * fp, String const * target) { String const * path; if((path = config_get(configure->config, target, "install")) == NULL) return; _makefile_mkdir(fp, path); _makefile_print(fp, "%s%s%s%s/%s\n", "\t$(INSTALL) -m 0644 $(OBJDIR)", target, " $(DESTDIR)", path, target); } static void _install_target_plugin(Configure * configure, FILE * fp, String const * target) { String const * path; String const * mode; mode_t m = 0755; String * p; if((path = config_get(configure->config, target, "install")) == NULL) return; if((mode = config_get(configure->config, target, "mode")) == NULL /* XXX these tests are not sufficient */ || mode[0] == '\0' || (m = strtol(mode, &p, 8)) == 0 || *p != '\0') mode = "0755"; _makefile_mkdir(fp, path); _makefile_print(fp, "%s%04o%s%s%s%s%s%s%s", "\t$(INSTALL) -m ", m, " $(OBJDIR)", target, "$(SOEXT) $(DESTDIR)", path, "/", target, "$(SOEXT)\n"); } static void _install_target_script(Configure * configure, FILE * fp, String const * target) { String const * path; String const * script; int phony; if((path = config_get(configure->config, target, "install")) == NULL) return; if((script = config_get(configure->config, target, "script")) == NULL) return; phony = _makefile_is_phony(configure, target); _makefile_print(fp, "\t%s%s%s%s%s%s%s", script, " -P \"$(DESTDIR)", (path[0] != '\0') ? path : "$(PREFIX)", "\" -i -- \"", phony ? "" : "$(OBJDIR)", target, "\"\n"); } static int _install_include(Configure * configure, FILE * fp, String const * include); static int _install_includes(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * includes; String * q; size_t i; char c; if((p = config_get(configure->config, NULL, "includes")) == NULL) return 0; if((includes = string_new(p)) == NULL) return 1; q = includes; for(i = 0; ret == 0; i++) { if(includes[i] != ',' && includes[i] != '\0') continue; c = includes[i]; includes[i] = '\0'; ret |= _install_include(configure, fp, includes); if(c == '\0') break; includes += i + 1; i = 0; } string_delete(q); return ret; } static int _install_include(Configure * configure, FILE * fp, String const * include) { Config * config = configure->config; char const * install; ssize_t i; String * p = NULL; if((install = config_get(config, include, "install")) == NULL) { install = "$(INCLUDEDIR)"; if((i = string_rindex(include, "/")) >= 0) if((p = string_new_length(include, i)) == NULL) return 2; } /* FIXME keep track of the directories created */ _makefile_print(fp, "%s%s", "\t$(MKDIR) $(DESTDIR)", install); if(p != NULL) { _makefile_print(fp, "/%s", p); string_delete(p); } _makefile_print(fp, "\n"); _makefile_print(fp, "%s%s%s%s/%s\n", "\t$(INSTALL) -m 0644 ", include, " $(DESTDIR)", install, include); return 0; } static int _dist_check(Configure * configure, char const * target, char const * mode); static int _dist_install(Configure * configure, FILE * fp, char const * directory, char const * mode, char const * filename); static int _install_dist(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * dist; String * q; size_t i; char c; String const * d; String const * mode; if((p = config_get(configure->config, NULL, "dist")) == NULL) return 0; if((dist = string_new(p)) == NULL) return 1; q = dist; for(i = 0;; i++) { if(dist[i] != ',' && dist[i] != '\0') continue; c = dist[i]; dist[i] = '\0'; if((mode = config_get(configure->config, dist, "mode")) == NULL) mode = "0644"; ret |= _dist_check(configure, dist, mode); if((d = config_get(configure->config, dist, "install")) != NULL) _dist_install(configure, fp, d, mode, dist); if(c == '\0') break; dist += i + 1; i = 0; } string_delete(q); return ret; } static int _dist_check(Configure * configure, char const * target, char const * mode) { char * p; mode_t m; m = strtol(mode, &p, 8); if(mode[0] == '\0' || *p != '\0') return error_set_print(PROGNAME, 1, "%s: %s%s%s", target, "Invalid permissions \"", mode, "\""); if((configure->prefs->flags & PREFS_S) && (m & 04000)) error_set_print(PROGNAME, 0, "%s: %s", target, "Installed as a SUID file"); if((configure->prefs->flags & PREFS_S) && (m & 04000)) error_set_print(PROGNAME, 0, "%s: %s", target, "Installed as a SGID file"); if((configure->prefs->flags & PREFS_S) && (m & 0111)) error_set_print(PROGNAME, 0, "%s: %s", target, "Installed as an executable file"); if((configure->prefs->flags & PREFS_S) && (m & 0020)) error_set_print(PROGNAME, 0, "%s: %s", target, "Installed as a group-writable file"); if((configure->prefs->flags & PREFS_S) && (m & 0002)) error_set_print(PROGNAME, 0, "%s: %s", target, "Installed as a writable file"); return 0; } static int _dist_install(Configure * configure, FILE * fp, char const * directory, char const * mode, char const * filename) { char sep = (configure->os != HO_WIN32) ? '/' : '\\'; String * p; char const * q; if(strchr(filename, sep) != NULL) { if((p = string_new(filename)) == NULL) return -1; q = dirname(p); /* FIXME keep track of the directories created */ _makefile_print(fp, "%s%s%c%s\n", "\t$(MKDIR) $(DESTDIR)", directory, sep, q); string_delete(p); } else _makefile_mkdir(fp, directory); _makefile_print(fp, "%s%s%s%s%s%s%c%s\n", "\t$(INSTALL) -m ", mode, " ", filename, " $(DESTDIR)", directory, sep, filename); return 0; } static int _write_phony_targets(Configure * configure, FILE * fp); static int _write_phony(Configure * configure, FILE * fp, char const ** targets) { size_t i; _makefile_print(fp, "%s:", "\n.PHONY"); for(i = 0; targets[i] != NULL; i++) _makefile_print(fp, " %s", targets[i]); if(_write_phony_targets(configure, fp) != 0) return 1; _makefile_print(fp, "%s", "\n"); return 0; } static int _write_phony_targets(Configure * configure, FILE * fp) { String const * p; String * prints; size_t i; char c; String const * type; if((p = config_get(configure->config, NULL, "targets")) == NULL) return 0; if((prints = string_new(p)) == NULL) return 1; for(i = 0;; i++) { if(prints[i] != ',' && prints[i] != '\0') continue; c = prints[i]; prints[i] = '\0'; if((type = config_get(configure->config, prints, "type")) != NULL) switch(enum_string(TT_LAST, sTargetType, type)) { case TT_SCRIPT: if(_makefile_is_phony(configure, prints)) _makefile_print(fp, " %s", prints); break; } if(c == '\0') break; prints += i + 1; i = 0; } return 0; } static int _uninstall_target(Configure * configure, FILE * fp, String const * target); static int _uninstall_include(Configure * configure, FILE * fp, String const * include); static int _uninstall_dist(Configure * configure, FILE * fp, String const * dist); static int _write_uninstall(Configure * configure, FILE * fp) { int ret = 0; String const * p; String * targets; String * q; String * includes; String * dist; size_t i; char c; _makefile_target(fp, "uninstall", NULL); if(config_get(configure->config, NULL, "subdirs") != NULL) _makefile_subdirs(fp, "uninstall"); if((p = config_get(configure->config, NULL, "targets")) != NULL) { if((targets = string_new(p)) == NULL) return 1; q = targets; for(i = 0; ret == 0; i++) { if(targets[i] != ',' && targets[i] != '\0') continue; c = targets[i]; targets[i] = '\0'; ret = _uninstall_target(configure, fp, targets); if(c == '\0') break; targets += i + 1; i = 0; } string_delete(q); } if((p = config_get(configure->config, NULL, "includes")) != NULL) { if((includes = string_new(p)) == NULL) return 1; q = includes; for(i = 0; ret == 0; i++) { if(includes[i] != ',' && includes[i] != '\0') continue; c = includes[i]; includes[i] = '\0'; ret = _uninstall_include(configure, fp, includes); if(c == '\0') break; includes += i + 1; i = 0; } string_delete(q); } if((p = config_get(configure->config, NULL, "dist")) != NULL) { if((dist = string_new(p)) == NULL) return 1; q = dist; for(i = 0; ret == 0; i++) { if(dist[i] != ',' && dist[i] != '\0') continue; c = dist[i]; dist[i] = '\0'; ret = _uninstall_dist(configure, fp, dist); if(c == '\0') break; dist += i + 1; i = 0; } string_delete(q); } return ret; } static int _uninstall_target_library(Configure * configure, FILE * fp, String const * target, String const * path); static void _uninstall_target_script(Configure * configure, FILE * fp, String const * target, String const * path); static int _uninstall_target(Configure * configure, FILE * fp, String const * target) { String const * type; String const * path; TargetType tt; const String rm_destdir[] = "$(RM) -- $(DESTDIR)"; if((type = config_get(configure->config, target, "type")) == NULL) return 1; if((path = config_get(configure->config, target, "install")) == NULL) return 0; tt = enum_string(TT_LAST, sTargetType, type); switch(tt) { case TT_BINARY: _makefile_print(fp, "\t%s%s/%s%s\n", rm_destdir, path, target, "$(EXEEXT)"); break; case TT_LIBRARY: if(_uninstall_target_library(configure, fp, target, path) != 0) return 1; break; case TT_LIBTOOL: _makefile_print(fp, "\t%s%s%s/%s%s", "$(LIBTOOL)" " --mode=uninstall ", rm_destdir, path, target, ".la\n"); break; case TT_OBJECT: _makefile_print(fp, "\t%s%s/%s\n", rm_destdir, path, target); break; case TT_PLUGIN: _makefile_print(fp, "\t%s%s/%s%s\n", rm_destdir, path, target, "$(SOEXT)"); break; case TT_SCRIPT: _uninstall_target_script(configure, fp, target, path); break; case TT_UNKNOWN: break; } return 0; } static int _uninstall_target_library(Configure * configure, FILE * fp, String const * target, String const * path) { String * soname; String const * p; const String format[] = "\t%s%s/%s%s%s%s"; const String rm_destdir[] = "$(RM) -- $(DESTDIR)"; if(configure_can_library_static(configure)) /* uninstall the static library */ _makefile_print(fp, format, rm_destdir, path, target, ".a\n", "", ""); if((p = config_get(configure->config, target, "soname")) != NULL) soname = string_new(p); else if(configure->os == HO_MACOSX) /* versioning is different on MacOS X */ soname = string_new_append(target, ".0.0$(SOEXT)", NULL); else if(configure->os == HO_WIN32) /* and on Windows */ soname = string_new_append(target, "$(SOEXT)", NULL); else soname = string_new_append(target, "$(SOEXT).0", NULL); if(soname == NULL) return 1; /* uninstall the shared library */ if(configure->os == HO_MACOSX) { _makefile_print(fp, format, rm_destdir, path, soname, "\n", "", ""); _makefile_print(fp, format, rm_destdir, path, target, ".0", "$(SOEXT)", "\n"); } else if(configure->os != HO_WIN32) { _makefile_print(fp, format, rm_destdir, path, soname, ".0\n", "", ""); _makefile_print(fp, format, rm_destdir, path, soname, "\n", "", ""); } _makefile_print(fp, format, rm_destdir, path, target, "$(SOEXT)", "\n", ""); string_delete(soname); return 0; } static void _uninstall_target_script(Configure * configure, FILE * fp, String const * target, String const * path) { String const * script; if((script = config_get(configure->config, target, "script")) == NULL) return; _makefile_print(fp, "\t%s%s%s%s%s%s", script, " -P \"$(DESTDIR)", (path[0] != '\0') ? path : "$(PREFIX)", "\" -u -- \"", target, "\"\n"); } static int _uninstall_include(Configure * configure, FILE * fp, String const * include) { Config * config = configure->config; String const * install; if((install = config_get(config, include, "install")) == NULL) install = "$(INCLUDEDIR)"; _makefile_print(fp, "%s%s/%s\n", "\t$(RM) -- $(DESTDIR)", install, include); return 0; } static int _uninstall_dist(Configure * configure, FILE * fp, String const * dist) { Config * config = configure->config; String const * install; if((install = config_get(config, dist, "install")) == NULL) return 0; _makefile_print(fp, "%s%s/%s\n", "\t$(RM) -- $(DESTDIR)", install, dist); return 0; } /* makefile_is_phony */ static int _makefile_is_phony(Configure * configure, char const * target) { String const * p; if((p = config_get(configure->config, target, "phony")) != NULL && strtol(p, NULL, 10) == 1) return 1; return 0; } /* useful */ /* makefile_expand */ static int _makefile_expand(FILE * fp, char const * field) { String * q; int res; if((q = string_new(field)) == NULL || string_replace(&q, ",", " ") != 0) { string_delete(q); return -1; } res = _makefile_print(fp, " %s", q); string_delete(q); return (res >= 0) ? 0 : -1; } /* makefile_link */ static int _makefile_link(FILE * fp, int symlink, char const * link, char const * path) { _makefile_print(fp, "\t$(LN)%s -- %s %s\n", symlink ? " -s" : "", link, path); return 0; } /* makefile_output_variable */ static int _makefile_output_variable(FILE * fp, char const * name, char const * value) { int res; char const * align; char const * equals; if(fp == NULL) return 0; if(name == NULL) return -1; if(value == NULL) value = ""; align = (strlen(name) >= 8) ? "" : "\t"; equals = (strlen(value) > 0) ? "= " : "="; res = _makefile_print(fp, "%s%s%s%s\n", name, align, equals, value); return (res >= 0) ? 0 : -1; } /* makefile_mkdir */ static int _makefile_mkdir(FILE * fp, char const * directory) { /* FIXME keep track of the directories created */ return _makefile_print(fp, "%s%s\n", "\t$(MKDIR) $(DESTDIR)", directory); } /* makefile_print */ static int _makefile_print(FILE * fp, char const * format, ...) { int ret; va_list ap; va_start(ap, format); if(fp == NULL) ret = vsnprintf(NULL, 0, format, ap); else ret = vfprintf(fp, format, ap); va_end(ap); return ret; } /* makefile_remove */ static int _makefile_remove(FILE * fp, int recursive, ...) { va_list ap; char const * sep = " -- "; char const * p; _makefile_print(fp, "\t$(RM)%s", recursive ? " -r" : ""); va_start(ap, recursive); while((p = va_arg(ap, char const * )) != NULL) { _makefile_print(fp, "%s%s", sep, p); sep = " "; } va_end(ap); _makefile_print(fp, "%c", '\n'); return 0; } /* makefile_subdirs */ static int _makefile_subdirs(FILE * fp, char const * target) { if(target != NULL) _makefile_print(fp, "\t@for i in $(SUBDIRS); do (cd \"$$i\" && \\\n" "\t\tif [ -n \"$(OBJDIR)\" ]; then \\\n" "\t\t$(MAKE) OBJDIR=\"$(OBJDIR)$$i/\" %s; \\\n" "\t\telse $(MAKE) %s; fi) || exit; done\n", target, target); else _makefile_print(fp, "%s", "\t@for i in $(SUBDIRS); do (cd \"$$i\" && \\\n" "\t\tif [ -n \"$(OBJDIR)\" ]; then \\\n" "\t\t([ -d \"$(OBJDIR)$$i\" ]" " || $(MKDIR) -- \"$(OBJDIR)$$i\") && \\\n" "\t\t$(MAKE) OBJDIR=\"$(OBJDIR)$$i/\"; \\\n" "\t\telse $(MAKE); fi) || exit; done\n"); return 0; } /* makefile_target */ static int _makefile_target(FILE * fp, char const * target, ...) { va_list ap; char const * sep = " "; char const * p; if(target == NULL) return -1; _makefile_print(fp, "\n%s:", target); va_start(ap, target); while((p = va_arg(ap, char const *)) != NULL) _makefile_print(fp, "%s%s", sep, p); va_end(ap); _makefile_print(fp, "%c", '\n'); return 0; } #ifdef WITH_UNUSED /* makefile_targetv */ static int _makefile_targetv(FILE * fp, char const * target, char const ** depends) { char const ** p; if(target == NULL) return -1; _makefile_print(fp, "\n%s:", target); if(depends != NULL) for(p = depends; *p != NULL; p++) _makefile_print(fp, " %s", *p); _makefile_print(fp, "%c", '\n'); return 0; } #endif