configure/src/makefile.c
2008-04-17 23:27:33 +00:00

1370 lines
35 KiB
C

/* $Id$ */
/* Copyright (c) 2007 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Devel configure */
/* configure is not free software; you can redistribute it and/or modify it
* under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike
* 3.0 Unported as published by the Creative Commons organization.
*
* configure is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the Creative Commons Attribution-NonCommercial-
* ShareAlike 3.0 Unported license for more details.
*
* You should have received a copy of the Creative Commons Attribution-
* NonCommercial-ShareAlike 3.0 along with configure; if not, browse to
* http://creativecommons.org/licenses/by-nc-sa/3.0/ */
#include <System.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "settings.h"
#include "configure.h"
ARRAY(Config *, config);
/* functions */
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, "/");
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%s%s", "Creating ", MAKEFILE, " in ",
directory, "\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_install(Configure * configure, FILE * fp);
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;
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_install(configure, fp) != 0
|| _write_uninstall(configure, fp) != 0)
return 1;
if(!(configure->prefs->flags & PREFS_n))
fprintf(fp, "%s%s%s%s%s", "\n.PHONY: all",
config_get(config, "", "subdirs") != NULL
? " subdirs" : "",
" clean distclean",
config_get(config, "", "package") != NULL
&& config_get(config, "", "version") != NULL
? " dist" : "",
" install uninstall\n");
return 0;
}
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_targets(Configure * configure, FILE * fp);
static int _variables_executables(Configure * configure, FILE * fp);
static int _variables_includes(Configure * configure, FILE * fp);
static int _write_variables(Configure * configure, FILE * fp)
{
int ret = 0;
String const * directory;
directory = config_get(configure->config, "", "directory");
ret |= _variables_package(configure, fp, directory);
ret |= _variables_print(configure, fp, "subdirs", "SUBDIRS");
ret |= _variables_targets(configure, fp);
ret |= _variables_executables(configure, fp);
ret |= _variables_includes(configure, fp);
if(!(configure->prefs->flags & PREFS_n))
fputc('\n', fp);
return ret;
}
static int _variables_package(Configure * configure, FILE * fp,
String const * directory)
{
String const * package;
String const * version;
String * p;
if((package = config_get(configure->config, "", "package")) == NULL)
return 0;
if(configure->prefs->flags & PREFS_v)
printf("%s%s", "Package: ", package);
if((version = config_get(configure->config, "", "version")) == NULL)
{
if(configure->prefs->flags & PREFS_v)
fputc('\n', stdout);
fprintf(stderr, "%s%s%s", "configure: ", directory,
": \"package\" needs \"version\"\n");
return 1;
}
if(configure->prefs->flags & PREFS_v)
printf(" %s\n", version);
if(fp != NULL)
fprintf(fp, "%s%s%s%s%s", "PACKAGE\t= ", package,
"\nVERSION\t= ", version, "\n");
if((p = config_get(configure->config, "", "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;
unsigned long i;
char c;
if(configure->prefs->flags & PREFS_n)
return 0;
if((p = config_get(configure->config, "", input)) == NULL)
return 0;
if((prints = strdup(p)) == NULL)
return error_set_code(1, "%s", strerror(errno));
fprintf(fp, "%s%s", output, "\t=");
for(i = 0;; i++)
{
if(prints[i] != ',' && prints[i] != '\0')
continue;
c = prints[i];
prints[i] = '\0';
fprintf(fp, " %s", prints);
if(c == '\0')
break;
prints[i] = c;
prints += i + 1;
i = 0;
}
fputc('\n', fp);
free(prints);
return 0;
}
static int _variables_targets(Configure * configure, FILE * fp)
{
String * prints;
unsigned long i;
char c;
String const * type;
if(configure->prefs->flags & PREFS_n)
return 0;
if((prints = config_get(configure->config, "", "targets")) == NULL)
return 0;
fprintf(fp, "%s%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)
fprintf(fp, " %s", prints);
else
switch(enum_string(TT_LAST, sTargetType, type))
{
case TT_BINARY:
case TT_OBJECT:
case TT_UNKNOWN:
fprintf(fp, " %s", prints);
break;
case TT_LIBRARY:
fprintf(fp, " %s%s%s%s", prints, ".a ",
prints, ".so");
break;
}
if(c == '\0')
break;
prints[i] = c;
prints+=i+1;
i = 0;
}
fputc('\n', fp);
return 0;
}
static int _executables_variables(Configure * configure, FILE * fp,
String const * target);
static int _variables_executables(Configure * configure, FILE * fp)
{
String * targets;
String * includes;
int i;
char c;
if(configure->prefs->flags & PREFS_n)
return 0;
targets = config_get(configure->config, "", "targets");
includes = config_get(configure->config, "", "includes");
if(targets != NULL)
{
for(i = 0;; i++)
{
if(targets[i] != ',' && targets[i] != '\0')
continue;
c = targets[i];
targets[i] = '\0';
_executables_variables(configure, fp, targets);
if(c == '\0')
break;
targets[i] = c;
targets+=i+1;
i = 0;
}
}
else if(includes != NULL)
{
fprintf(fp, "%s%s\n", "PREFIX\t= ", configure->prefs->prefix);
fprintf(fp, "%s%s\n", "DESTDIR\t= ", configure->prefs->destdir);
}
if(targets != NULL || includes != NULL)
fprintf(fp, "%s", "RM\t= rm -f\n");
if(config_get(configure->config, "", "package"))
{
if(targets == NULL && includes == NULL)
fprintf(fp, "%s", "RM\t= rm -f\n");
fprintf(fp, "%s", "LN\t= ln -sf\nTAR\t= tar -czvf\n");
}
if(targets != NULL || includes != NULL)
{
fprintf(fp, "%s", "MKDIR\t= mkdir -p\n");
fprintf(fp, "%s", "INSTALL\t= install\n");
}
return 0;
}
static void _variables_binary(Configure * configure, FILE * fp, char * done);
static void _variables_library(Configure * configure, FILE * fp, char * done);
static int _executables_variables(Configure * configure, FILE * fp,
String const * target)
{
static Config * flag = NULL;
String const * type;
char done[TT_LAST]; /* FIXME even better if'd be variable by variable */
TargetType tt;
if(flag != configure->config)
{
flag = configure->config;
memset(done, 0, sizeof(done));
}
if((type = config_get(configure->config, target, "type")) == NULL)
return 0;
if(done[(tt = enum_string(TT_LAST, sTargetType, type))])
return 0;
switch(tt)
{
case TT_BINARY:
_variables_binary(configure, fp, done);
break;
case TT_LIBRARY:
_variables_library(configure, fp, done);
break;
case TT_OBJECT:
case TT_UNKNOWN:
break;
}
done[tt] = 1;
return 0;
}
static void _targets_cflags(Configure * configure, FILE * fp);
static void _targets_cxxflags(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 const * p;
if(!done[TT_LIBRARY])
{
fprintf(fp, "%s%s\n", "PREFIX\t= ", configure->prefs->prefix);
fprintf(fp, "%s%s\n", "DESTDIR\t= ", configure->prefs->destdir);
}
if(configure->prefs->bindir[0] == '/')
fprintf(fp, "%s%s\n", "BINDIR\t= ", configure->prefs->bindir);
else
fprintf(fp, "%s%s\n", "BINDIR\t= $(PREFIX)/",
configure->prefs->bindir);
if(!done[TT_LIBRARY])
{
_targets_cflags(configure, fp);
_targets_cxxflags(configure, fp);
}
if((p = config_get(configure->config, "", "ldflags_force")) != NULL)
{
fprintf(fp, "%s", "LDFLAGSF= ");
_binary_ldflags(configure, fp, p);
}
if((p = config_get(configure->config, "", "ldflags")) != NULL)
{
fprintf(fp, "%s", "LDFLAGS\t= ");
_binary_ldflags(configure, fp, p);
}
}
static void _targets_cflags(Configure * configure, FILE * fp)
{
String const * cc;
String const * cff;
String const * cf;
String const * cpp;
String const * as;
String const * asf;
cpp = config_get(configure->config, "", "cppflags");
cc = config_get(configure->config, "", "cc");
if((cff = config_get(configure->config, "", "cflags_force")) != NULL)
{
fprintf(fp, "%s%s%s", "CC\t= ", cc != NULL ? cc : "cc",
"\nCPPFLAGS=");
if(cpp != NULL)
fprintf(fp, " %s", cpp);
fprintf(fp, "%s%s", "\nCFLAGSF\t= ", cff);
if(configure->os == HO_GNU_LINUX && string_find(cff, "-ansi"))
fputs(" -D _GNU_SOURCE", fp); /* FIXME undup */
fputc('\n', fp);
}
if((cf = config_get(configure->config, "", "cflags")) != NULL)
{
if(cff == NULL)
{
fprintf(fp, "%s%s%s", "CC\t= ", cc != NULL ? cc : "cc",
"\nCPPFLAGS=");
if(cpp != NULL)
fprintf(fp, " %s", cpp);
fputc('\n', fp);
}
fprintf(fp, "%s%s", "CFLAGS\t= ", cf);
if(configure->os == HO_GNU_LINUX && string_find(cf, "-ansi"))
fputs(" -D _GNU_SOURCE", fp);
fputc('\n', fp);
}
as = config_get(configure->config, "", "as");
asf = config_get(configure->config, "", "asflags");
if(as != NULL || asf != NULL)
fprintf(fp, "%s%s%s%s\n", "AS\t= ", as != NULL ? as : "as",
"\nASFLAGS\t= ", asf);
}
static void _targets_cxxflags(Configure * configure, FILE * fp)
{
String const * p;
String const * q;
if((p = config_get(configure->config, "", "cxxflags_force")) != NULL)
{
fprintf(fp, "%s%s", "CXX\t= c++\nCXXFLAGSF= ", p);
if(configure->os == HO_GNU_LINUX && string_find(p, "-ansi"))
fprintf(fp, "%s", " -D _GNU_SOURCE");
fputc('\n', fp);
}
if((q = config_get(configure->config, "", "cxxflags")) != NULL)
{
if(p == NULL)
fprintf(fp, "%s", "CXX\t= c++\n");
fprintf(fp, "%s%s", "CXXFLAGS= ", q);
if(configure->os == HO_GNU_LINUX && string_find(q, "-ansi"))
fprintf(fp, "%s", " -D _GNU_SOURCE");
fputc('\n', fp);
}
}
static void _binary_ldflags(Configure * configure, FILE * fp,
String const * ldflags)
{
char * libs_gnu[] = { "socket", NULL };
char * libs_bsd[] = { "crypt", "dl", "socket", NULL };
char * libs_sunos[] = { "dl", NULL };
char buf[10];
char ** libs;
String * p;
String * q;
int i;
if((p = string_new(ldflags)) == NULL)
{
fprintf(fp, "%s%s", ldflags, "\n");
return;
}
switch(configure->os)
{
case HO_GNU_LINUX:
libs = libs_gnu;
break;
case HO_FREEBSD:
case HO_NETBSD:
case HO_OPENBSD:
libs = libs_bsd;
break;
case HO_SUNOS:
libs = libs_sunos;
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)
continue;
memmove(q, q + strlen(buf), strlen(q) - strlen(buf) + 1);
}
fprintf(fp, "%s\n", p);
free(p);
}
static void _variables_library(Configure * configure, FILE * fp, char * done)
{
if(!done[TT_LIBRARY])
{
fprintf(fp, "%s%s\n", "PREFIX\t= ", configure->prefs->prefix);
fprintf(fp, "%s%s\n", "DESTDIR\t= ", configure->prefs->destdir);
}
if(configure->prefs->libdir[0] == '/')
fprintf(fp, "%s%s\n", "LIBDIR\t= ", configure->prefs->libdir);
else
fprintf(fp, "%s%s\n", "LIBDIR\t= $(PREFIX)/",
configure->prefs->libdir);
if(!done[TT_BINARY])
{
_targets_cflags(configure, fp);
_targets_cxxflags(configure, fp);
}
fputs("AR\t= ar -rc\nRANLIB\t= ranlib\nLD\t= ld -shared\n", fp);
}
static int _variables_includes(Configure * configure, FILE * fp)
{
String const * includes;
if((includes = config_get(configure->config, "", "includes")) == NULL)
return 0;
if(fp == NULL)
return 0;
if(configure->prefs->includedir[0] == '/')
fprintf(fp, "%s%s\n", "INCLUDEDIR= ",
configure->prefs->includedir);
else
fprintf(fp, "%s%s\n", "INCLUDEDIR= $(PREFIX)/",
configure->prefs->includedir);
return 0;
}
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;
char const * p;
char * targets;
char c;
int i;
if(_targets_all(configure, fp) != 0
|| _targets_subdirs(configure, fp) != 0)
return 1;
if((p = config_get(configure->config, "", "targets")) == NULL)
return 0;
if((targets = strdup(p)) == NULL)
return error_set_code(1, "%s", strerror(errno));
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] = c;
targets += i+1;
i = 0;
}
free(targets);
return ret;
}
static int _targets_all(Configure * configure, FILE * fp)
{
if(configure->prefs->flags & PREFS_n)
return 0;
fprintf(fp, "%s", "\nall:");
if(config_get(configure->config, "", "subdirs") != NULL)
fprintf(fp, "%s", " subdirs");
if(config_get(configure->config, "", "targets") != NULL)
fprintf(fp, "%s", " $(TARGETS)");
fprintf(fp, "%s", "\n");
return 0;
}
static int _targets_subdirs(Configure * configure, FILE * fp)
{
String * subdirs;
if(configure->prefs->flags & PREFS_n)
return 0;
if((subdirs = config_get(configure->config, "", "subdirs")) != NULL)
fprintf(fp, "%s", "\nsubdirs:\n\t@for i in $(SUBDIRS); do"
" (cd $$i && $(MAKE)) || exit; done\n");
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_object(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", "configure: ", 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_OBJECT:
return _target_object(configure, fp, target);
case TT_UNKNOWN:
fprintf(stderr, "%s%s%s", "configure: ", target,
": unknown type for target\n");
return 1;
}
return 0;
}
static int _objs_source(Prefs * prefs, FILE * fp, String * source);
static int _target_objs(Configure * configure, FILE * fp,
String const * target)
{
int ret = 0;
String * sources;
int i;
char c;
if((sources = config_get(configure->config, target, "sources")) == NULL)
{
fprintf(stderr, "%s%s%s", "configure: ", target,
": no sources defined for target\n");
return 1;
}
if(!(configure->prefs->flags & PREFS_n))
fprintf(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(configure->prefs, fp, sources);
if(c == '\0')
break;
sources[i] = c;
sources+=i+1;
i = 0;
}
if(!(configure->prefs->flags & PREFS_n))
fputc('\n', fp);
return ret;
}
static int _objs_source(Prefs * prefs, FILE * fp, String * source)
{
int ret = 0;
String * extension;
size_t len;
if((extension = _source_extension(source)) == NULL)
{
fprintf(stderr, "%s%s%s", "configure: ", source,
": no extension for source\n");
return 1;
}
len = string_length(source) - string_length(extension) - 1;
source[len] = '\0';
switch(enum_string(OT_LAST, sObjectType, extension))
{
case OT_ASM_SOURCE:
case OT_C_SOURCE:
if(prefs->flags & PREFS_n)
break;
fprintf(fp, "%s%s%s", " ", source, ".o");
break;
case OT_CXX_SOURCE:
case OT_CPP_SOURCE:
if(prefs->flags & PREFS_n)
break;
fprintf(fp, "%s%s%s", " ", source, ".o");
break;
case OT_UNKNOWN:
ret = 1;
fprintf(stderr, "%s%s%s", "configure: ", source,
": unknown extension for source\n");
break;
}
source[len] = '.';
return ret;
}
static void _target_flags(Configure * configure, FILE * fp,
String const * target);
static int _target_binary(Configure * configure, FILE * fp,
String const * target)
{
String * p;
if(_target_objs(configure, fp, target) != 0)
return 1;
if(configure->prefs->flags & PREFS_n)
return 0;
_target_flags(configure, fp, target);
fprintf(fp, "\n%s%s%s%s", target, ": $(", target, "_OBJS)\n");
fprintf(fp, "%s%s%s%s%s", "\t$(CC) -o ", target, " $(", target, "_OBJS)"
" $(LDFLAGSF) $(LDFLAGS)");
if((p = config_get(configure->config, target, "ldflags")) != NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
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 void _target_flags(Configure * configure, FILE * fp,
String const * target)
{
char done[OT_LAST+1];
String * sources;
String * extension;
ObjectType type;
char c;
unsigned int i;
memset(done, 0, sizeof(done));
if((sources = config_get(configure->config, target, "sources")) == NULL)
return;
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 = enum_string(OT_LAST, sObjectType, extension);
sources[i] = c;
if(!done[type])
switch(type)
{
case OT_ASM_SOURCE:
_flags_asm(configure, fp, target);
break;
case OT_C_SOURCE:
_flags_c(configure, fp, target);
break;
case OT_CXX_SOURCE:
case OT_CPP_SOURCE:
done[OT_CXX_SOURCE] = 1;
done[OT_CPP_SOURCE] = 1;
_flags_cxx(configure, fp, target);
break;
case OT_UNKNOWN:
break;
}
done[type] = 1;
if(c == '\0')
break;
sources+=i+1;
i = 0;
}
}
static void _flags_asm(Configure * configure, FILE * fp, String const * target)
{
String const * p;
fprintf(fp, "%s%s", target, "_ASFLAGS = $(CPPFLAGS) $(ASFLAGS)");
if((p = config_get(configure->config, target, "asflags")) != NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
}
static void _flags_c(Configure * configure, FILE * fp, String const * target)
{
String const * p;
fprintf(fp, "%s%s", target, "_CFLAGS = $(CPPFLAGS)");
if((p = config_get(configure->config, target, "cppflags")) != NULL)
fprintf(fp, " %s", p);
fprintf(fp, "%s", " $(CFLAGSF) $(CFLAGS)");
if((p = config_get(configure->config, target, "cflags")) != NULL)
{
fprintf(fp, " %s", p);
if(configure->os == HO_GNU_LINUX && string_find(p, "-ansi"))
fprintf(fp, "%s", " -D _GNU_SOURCE");
}
fputc('\n', fp);
}
static void _flags_cxx(Configure * configure, FILE * fp, String const * target)
{
String const * p;
fprintf(fp, "%s%s", target, "_CXXFLAGS = $(CXXFLAGSF) $(CXXFLAGS)");
if((p = config_get(configure->config, target, "cxxflags")) != NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
}
static int _target_library(Configure * configure, FILE * fp,
String const * target)
{
String const * p;
if(_target_objs(configure, fp, target) != 0)
return 1;
if(configure->prefs->flags & PREFS_n)
return 0;
_target_flags(configure, fp, target);
fprintf(fp, "\n%s%s%s%s", target, ".a: $(", target, "_OBJS)\n");
fprintf(fp, "%s%s%s%s%s", "\t$(AR) ", target, ".a $(", target,
"_OBJS)\n");
fprintf(fp, "%s%s%s", "\t$(RANLIB) ", target, ".a\n");
fprintf(fp, "\n%s%s%s%s", target, ".so: $(", target, "_OBJS)\n");
fprintf(fp, "%s%s%s%s%s", "\t$(LD) -o ", target, ".so $(", target,
"_OBJS)");
if((p = config_get(configure->config, target, "ldflags")) != NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
return 0;
}
static int _target_object(Configure * configure, FILE * fp,
String const * target)
{
String * p;
String * extension;
if((p = config_get(configure->config, target, "sources")) == NULL)
{
fprintf(stderr, "%s%s%s", "configure: ", target,
": No sources for target\n");
return 1;
}
if(strchr(p, ',') != NULL)
{
fprintf(stderr, "%s%s%s", "configure: ", target,
": An object can have only one source file\n");
return 1;
}
if(configure->prefs->flags & PREFS_n)
return 0;
if((extension = _source_extension(p)) == NULL)
return 1;
switch(enum_string(OT_LAST, sObjectType, extension))
{
case OT_ASM_SOURCE:
fprintf(fp, "\n%s%s%s\n%s%s", target, "_OBJS = ",
target, target, "_ASFLAGS = $(CPPFLAGS)"
" $(ASFLAGS)");
if((p = config_get(configure->config, p, "asflags"))
!= NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
break;
case OT_C_SOURCE:
fprintf(fp, "\n%s%s%s\n%s%s", target, "_OBJS = ",
target, target, "_CFLAGS = $(CPPFLAGS)"
" $(CFLAGSF) $(CFLAGS)");
if((p = config_get(configure->config, p, "cflags"))
!= NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
break;
case OT_CXX_SOURCE:
case OT_CPP_SOURCE:
fprintf(fp, "\n%s%s%s\n%s%s", target, "_OBJS = ",
target, target, "_CXXFLAGS ="
" $(CPPFLAGS) $(CXXFLAGS)");
if((p = config_get(configure->config, p, "cxxflags"))
!= NULL)
fprintf(fp, " %s", p);
fputc('\n', fp);
break;
case OT_UNKNOWN:
fprintf(stderr, "%s%s%s", "configure: ", target,
": Unknown source type for object\n");
return 1;
}
return 0;
}
static int _objects_target(Configure * configure, FILE * fp,
String const * target);
static int _write_objects(Configure * configure, FILE * fp)
{
char * targets = config_get(configure->config, "", "targets");
char c;
int i;
int ret = 0;
if(targets == NULL)
return 0;
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] = c;
targets+=i+1;
i = 0;
}
return ret;
}
static int _target_source(Configure * configure, FILE * fp,
String const * target, String * source);
static int _objects_target(Configure * configure, FILE * fp,
String const * target)
{
String * sources;
int i;
char c;
if((sources = config_get(configure->config, target, "sources")) == NULL)
return 0;
for(i = 0;; i++)
{
if(sources[i] != ',' && sources[i] != '\0')
continue;
c = sources[i];
sources[i] = '\0';
_target_source(configure, fp, target, sources);
if(c == '\0')
break;
sources[i] = c;
sources+=i+1;
i = 0;
}
return 0;
}
static void _source_depends(Config * config, FILE * fp, String const * source);
static int _target_source(Configure * configure, FILE * fp,
String const * target, String * source)
{
int ret = 0;
String * extension;
ObjectType ot;
size_t len;
String const * p;
if((extension = _source_extension(source)) == NULL)
return 1;
len = string_length(source) - string_length(extension) - 1;
source[len] = '\0';
switch((ot = enum_string(OT_LAST, sObjectType, extension)))
{
case OT_ASM_SOURCE:
if(configure->prefs->flags & PREFS_n)
break;
fprintf(fp, "%s%s%s%s%s%s", "\n", source, ".o: ",
source, ".", sObjectType[ot]);
source[len] = '.'; /* FIXME ugly */
_source_depends(configure->config, fp, source);
p = config_get(configure->config, source, "asflags");
source[len] = '\0';
fprintf(fp, "%s%s%s", "\n\t$(AS) $(", target,
"_ASFLAGS)");
if(p != NULL)
fprintf(fp, " %s", p);
fprintf(fp, "%s%s%s%s%s%s", " -o ", source, ".o ",
source, ".", sObjectType[ot]);
fputc('\n', fp);
break;
case OT_C_SOURCE:
if(configure->prefs->flags & PREFS_n)
break;
fprintf(fp, "%s%s%s%s%s%s", "\n", source, ".o: ",
source, ".", sObjectType[ot]);
source[len] = '.'; /* FIXME ugly */
_source_depends(configure->config, fp, source);
p = config_get(configure->config, source, "cflags");
source[len] = '\0';
fprintf(fp, "%s%s%s", "\n\t$(CC) $(", target,
"_CFLAGS)");
if(p != NULL)
{
fprintf(fp, " %s", p);
if(configure->os == HO_GNU_LINUX
&& string_find(p, "-ansi"))
fputs(" -D _GNU_SOURCE", fp);
}
if(string_find(source, "/"))
fprintf(fp, "%s%s%s", " -o ", source, ".o");
fprintf(fp, "%s%s%s%s", " -c ", source, ".",
sObjectType[ot]);
fputc('\n', fp);
break;
case OT_CXX_SOURCE:
case OT_CPP_SOURCE:
if(configure->prefs->flags & PREFS_n)
break;
fprintf(fp, "%s%s%s%s%s%s", "\n", source, ".o: ",
source, ".", sObjectType[ot]);
source[len] = '.'; /* FIXME ugly */
_source_depends(configure->config, fp, source);
p = config_get(configure->config, source, "cxxflags");
source[len] = '\0';
fprintf(fp, "%s%s%s", "\n\t$(CXX) $(", target,
"_CXXFLAGS)");
if(p != NULL)
fprintf(fp, " %s", p);
if(string_find(source, "/"))
fprintf(fp, "%s%s%s", " -o ", source, ".o");
fprintf(fp, "%s%s%s%s", " -c ", source, ".",
sObjectType[ot]);
fputc('\n', fp);
break;
case OT_UNKNOWN:
ret = 1;
break;
}
source[len] = '.';
return ret;
}
static void _source_depends(Config * config, FILE * fp, String const * source)
{
String * depends;
int i;
char c;
if((depends = config_get(config, source, "depends")) == NULL)
return;
for(i = 0;; i++)
{
if(depends[i] != ',' && depends[i] != '\0')
continue;
c = depends[i];
depends[i] = '\0';
fprintf(fp, " %s", depends);
if(c == '\0')
break;
depends[i] = c;
depends+=i+1;
i = 0;
}
}
static int _clean_targets(Config * config, FILE * fp);
static int _write_clean(Configure * configure, FILE * fp)
{
if(configure->prefs->flags & PREFS_n)
return 0;
fputs("\nclean:\n", fp);
if(config_get(configure->config, "", "subdirs") != NULL)
fputs("\t@for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean)"
" || exit; done\n", fp);
return _clean_targets(configure->config, fp);
}
static int _clean_targets(Config * config, FILE * fp)
{
String * targets;
int i;
char c;
if((targets = config_get(config, "", "targets")) == NULL)
return 0;
fputs("\t$(RM)", fp);
for(i = 0;; i++)
{
if(targets[i] != ',' && targets[i] != '\0')
continue;
c = targets[i];
targets[i] = '\0';
fprintf(fp, "%s%s%s", " $(", targets, "_OBJS)");
if(c == '\0')
break;
targets[i] = c;
targets+=i+1;
i = 0;
}
fputc('\n', fp);
return 0;
}
static int _write_distclean(Configure * configure, FILE * fp)
{
String * subdirs;
if(configure->prefs->flags & PREFS_n)
return 0;
fputs("\ndistclean:", fp);
if((subdirs = config_get(configure->config, "", "subdirs")) == NULL)
fputs(" clean\n", fp);
else
{
fputs("\n\t@for i in $(SUBDIRS); do (cd $$i"
" && $(MAKE) distclean) || exit; done\n", fp);
_clean_targets(configure->config, fp);
}
if(config_get(configure->config, "", "targets") != NULL)
fputs("\t$(RM) $(TARGETS)\n", fp);
return 0;
}
static int _dist_subdir(Config * config, 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;
if(configure->prefs->flags & PREFS_n)
return 0;
package = config_get(configure->config, "", "package");
version = config_get(configure->config, "", "version");
if(package == NULL || version == NULL)
return 0;
fputs("\ndist:\n\t$(RM) -r $(PACKAGE)-$(VERSION)\n"
"\t$(LN) . $(PACKAGE)-$(VERSION)\n"
"\t@$(TAR) $(PACKAGE)-$(VERSION).tar.gz \\\n", fp);
for(i = from + 1; i < to; i++)
{
array_get_copy(ca, i, &p);
_dist_subdir(configure->config, fp, p);
}
if(from < to)
{
array_get_copy(ca, from, &p);
_dist_subdir(configure->config, fp, p);
}
else
return 1;
fputs("\t$(RM) $(PACKAGE)-$(VERSION)\n", fp);
return 0;
}
static int _dist_subdir_dist(FILE * fp, String * path, String * dist);
static int _dist_subdir(Config * config, FILE * fp, Config * subdir)
{
String * path;
size_t len;
String * targets;
String * includes;
String * dist;
int i;
char c;
path = config_get(config, "", "directory");
len = string_length(path);
path = config_get(subdir, "", "directory");
path = &path[len];
if(path[0] == '/')
path++;
if((targets = config_get(subdir, "", "targets")) != NULL)
/* FIXME unique SOURCES */
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] = c;
targets+=i+1;
i = 0;
}
if((includes = config_get(subdir, "", "includes")) != NULL)
_dist_subdir_dist(fp, path, includes);
if((dist = config_get(subdir, "", "dist")) != NULL)
_dist_subdir_dist(fp, path, dist);
fprintf(fp, "%s%s%s%s%s", "\t\t$(PACKAGE)-$(VERSION)/", path,
path[0] == '\0' ? "" : "/", PROJECT_CONF,
path[0] == '\0' ? "\n" : " \\\n");
return 0;
}
static int _dist_subdir_dist(FILE * fp, String * path, String * dist)
{
int i;
char c;
for(i = 0;; i++)
{
if(dist[i] != ',' && dist[i] != '\0')
continue;
c = dist[i];
dist[i] = '\0';
fprintf(fp, "%s%s%s%s%s", "\t\t$(PACKAGE)-$(VERSION)/",
path[0] == '\0' ? "" : path,
path[0] == '\0' ? "" : "/", dist, " \\\n");
if(c == '\0')
break;
dist[i] = c;
dist+=i+1;
i = 0;
}
return 0;
}
static int _install_target(Config * config, FILE * fp, String * target);
static int _install_include(Config * config, FILE * fp, String * include);
static int _write_install(Configure * configure, FILE * fp)
{
int ret = 0;
String const * subdirs;
String * targets;
String * includes;
int i;
char c;
if(configure->prefs->flags & PREFS_n)
return 0;
fputs("\ninstall: all\n", fp);
if((subdirs = config_get(configure->config, "", "subdirs")) != NULL)
fputs("\t@for i in $(SUBDIRS); do (cd $$i && $(MAKE) install)"
" || exit; done\n", fp);
if((targets = config_get(configure->config, "", "targets")) != NULL)
for(i = 0; ret == 0; i++)
{
if(targets[i] != ',' && targets[i] != '\0')
continue;
c = targets[i];
targets[i] = '\0';
ret |= _install_target(configure->config, fp, targets);
if(c == '\0')
break;
targets[i] = c;
targets += i + 1;
i = 0;
}
if((includes = config_get(configure->config, "", "includes")) != NULL)
for(i = 0; ret == 0; i++)
{
if(includes[i] != ',' && includes[i] != '\0')
continue;
c = includes[i];
includes[i] = '\0';
ret |= _install_include(configure->config, fp,
includes);
if(c == '\0')
break;
includes[i] = c;
includes += i + 1;
i = 0;
}
return ret;
}
static int _install_target(Config * config, FILE * fp, String * target)
{
static Config * flag = NULL;
static int done[TT_LAST];
String const * type;
TargetType tt;
if((type = config_get(config, target, "type")) == NULL)
return 1;
if(flag != config)
{
flag = config;
memset(done, 0, sizeof(done));
}
switch((tt = enum_string(TT_LAST, sTargetType, type)))
{
case TT_BINARY:
if(!done[tt])
fputs("\t$(MKDIR) $(DESTDIR)$(BINDIR)\n", fp);
fprintf(fp, "%s%s%s%s%s", "\t$(INSTALL) -m 0755 ",
target, " $(DESTDIR)$(BINDIR)/",
target, "\n");
break;
case TT_LIBRARY:
if(!done[tt])
fputs("\t$(MKDIR) $(DESTDIR)$(LIBDIR)\n", fp);
fprintf(fp, "%s%s%s%s%s", "\t$(INSTALL) -m 0644 ",
target, ".a $(DESTDIR)$(LIBDIR)/",
target, ".a\n");
fprintf(fp, "%s%s%s%s%s", "\t$(INSTALL) -m 0755 ",
target, ".so $(DESTDIR)$(LIBDIR)/",
target, ".so\n");
break;
case TT_OBJECT:
case TT_UNKNOWN:
break;
}
done[tt] = 1;
return 0;
}
static int _install_include(Config * config, FILE * fp, String * include)
{
static Config * flag = NULL;
static int done;
if(flag != config)
{
flag = config;
done = 0;
}
if(!done)
fputs("\t$(MKDIR) $(DESTDIR)$(INCLUDEDIR)\n", fp);
fprintf(fp, "%s%s%s%s%s", "\t$(INSTALL) -m 0644 ", include,
" $(DESTDIR)$(INCLUDEDIR)/", include, "\n");
done = 1;
return 0;
}
static int _uninstall_target(Config * config, FILE * fp, String * target);
static int _uninstall_include(FILE * fp, String * include);
static int _write_uninstall(Configure * configure, FILE * fp)
{
int ret = 0;
String const * subdirs;
String * targets;
String * includes;
int i;
char c;
if(configure->prefs->flags & PREFS_n)
return 0;
fputs("\nuninstall:\n", fp);
if((subdirs = config_get(configure->config, "", "subdirs")) != NULL)
fputs("\t@for i in $(SUBDIRS); do (cd $$i &&"
" $(MAKE) uninstall) || exit; done\n", fp);
if((targets = config_get(configure->config, "", "targets")) != NULL)
for(i = 0; ret == 0; i++)
{
if(targets[i] != ',' && targets[i] != '\0')
continue;
c = targets[i];
targets[i] = '\0';
ret = _uninstall_target(configure->config, fp, targets);
if(c == '\0')
break;
targets[i] = c;
targets += i + 1;
i = 0;
}
if((includes = config_get(configure->config, "", "includes")) != NULL)
for(i = 0; ret == 0; i++)
{
if(includes[i] != ',' && includes[i] != '\0')
continue;
c = includes[i];
includes[i] = '\0';
ret = _uninstall_include(fp, includes);
if(c == '\0')
break;
includes[i] = c;
includes += i + 1;
i = 0;
}
return ret;
}
static int _uninstall_target(Config * config, FILE * fp, String * target)
{
String const * type;
if((type = config_get(config, target, "type")) == NULL)
return 1;
switch(enum_string(TT_LAST, sTargetType, type))
{
case TT_BINARY:
fprintf(fp, "%s%s%s", "\t$(RM) $(DESTDIR)$(BINDIR)/",
target, "\n");
break;
case TT_LIBRARY:
fprintf(fp, "%s%s%s", "\t$(RM) $(DESTDIR)$(LIBDIR)/",
target, ".a\n");
fprintf(fp, "%s%s%s", "\t$(RM) $(DESTDIR)$(LIBDIR)/",
target, ".so\n");
break;
case TT_OBJECT:
case TT_UNKNOWN:
break;
}
return 0;
}
static int _uninstall_include(FILE * fp, String * include)
{
fprintf(fp, "%s%s%s", "\t$(RM) $(DESTDIR)$(INCLUDEDIR)/", include,
"\n");
return 0;
}