389 lines
8.7 KiB
C
389 lines
8.7 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 <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "makefile.h"
|
|
#include "configure.h"
|
|
#include "../config.h"
|
|
|
|
#ifndef PACKAGE
|
|
# define PACKAGE "configure"
|
|
#endif
|
|
|
|
|
|
/* configure */
|
|
/* variables */
|
|
const String * sHostArch[HA_COUNT] =
|
|
{
|
|
"i386", "i486", "i586", "i686",
|
|
"amd64",
|
|
"sparc", "sparc64",
|
|
"sun4u",
|
|
"zaurus",
|
|
"unknown"
|
|
};
|
|
const String * sHostOS[HO_COUNT] =
|
|
{
|
|
"Linux",
|
|
"FreeBSD", "NetBSD", "OpenBSD",
|
|
"SunOS",
|
|
"unknown"
|
|
};
|
|
const struct HostKernel sHostKernel[] =
|
|
{
|
|
{ HO_GNU_LINUX, "2.0" },
|
|
{ HO_GNU_LINUX, "2.2" },
|
|
{ HO_GNU_LINUX, "2.4" },
|
|
{ HO_GNU_LINUX, "2.6" },
|
|
{ HO_NETBSD, "2.0" },
|
|
{ HO_NETBSD, "3.0" },
|
|
{ HO_NETBSD, "4.0" },
|
|
{ HO_OPENBSD, "4.0" },
|
|
{ HO_OPENBSD, "4.1" },
|
|
{ HO_SUNOS, "5.7", },
|
|
{ HO_SUNOS, "5.8", },
|
|
{ HO_SUNOS, "5.9", },
|
|
{ HO_SUNOS, "5.10", },
|
|
{ HO_UNKNOWN, "unknown" }
|
|
};
|
|
|
|
const String * sTargetType[TT_COUNT] = { "binary", "library", "object", NULL };
|
|
const String * sObjectType[OT_COUNT] = { "c", "cc", "cpp", "S", NULL };
|
|
|
|
String * _source_extension(String * source)
|
|
{
|
|
int len;
|
|
|
|
for(len = string_length(source)-1; len >= 0; len--)
|
|
if(source[len] == '.')
|
|
return &source[len+1];
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* functions */
|
|
int configure_error(char const * message, int ret)
|
|
{
|
|
fputs(PACKAGE ": ", stderr);
|
|
perror(message);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int enum_string(int last, const String * strings[], String const * str)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < last; i++)
|
|
if(string_compare(strings[i], str) == 0)
|
|
return i;
|
|
return last;
|
|
}
|
|
|
|
|
|
int enum_string_short(int last, const String * strings[], String const * str)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < last; i++)
|
|
if(string_compare_length(strings[i], str,
|
|
string_length(strings[i])) == 0)
|
|
return i;
|
|
return last;
|
|
}
|
|
|
|
|
|
/* Configure */
|
|
static void _configure_detect(Configure * configure);
|
|
static int _configure_load(Prefs * prefs, char const * directory,
|
|
configArray * ca);
|
|
static int _configure_do(Configure * configure, configArray * ca);
|
|
static int _configure(Prefs * prefs, char const * directory)
|
|
{
|
|
Configure cfgr;
|
|
configArray * ca;
|
|
int ret;
|
|
int flags = prefs->flags;
|
|
int i;
|
|
Config * p;
|
|
|
|
if((ca = configarray_new()) == NULL)
|
|
return configure_error("libSystem", 2);
|
|
cfgr.prefs = prefs;
|
|
_configure_detect(&cfgr);
|
|
ret = _configure_load(prefs, directory, ca);
|
|
if(ret == 0)
|
|
{
|
|
if(prefs->flags & PREFS_n)
|
|
ret = _configure_do(&cfgr, ca);
|
|
else
|
|
{
|
|
prefs->flags = PREFS_n;
|
|
if(_configure_do(&cfgr, ca) == 0)
|
|
{
|
|
prefs->flags = flags;
|
|
ret = _configure_do(&cfgr, ca);
|
|
}
|
|
}
|
|
}
|
|
for(i = array_count(ca); i > 0; i--)
|
|
{
|
|
array_get_copy(ca, i - 1, &p);
|
|
config_delete(p);
|
|
}
|
|
array_delete(ca);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* private */
|
|
static HostKernel _detect_kernel(HostOS os, char const * release);
|
|
static void _configure_detect(Configure * configure)
|
|
{
|
|
struct utsname un;
|
|
|
|
if(uname(&un) < 0)
|
|
{
|
|
configure_error("system detection failed", 0);
|
|
configure->arch = HA_UNKNOWN;
|
|
configure->os = HO_UNKNOWN;
|
|
configure->kernel = HK_UNKNOWN;
|
|
return;
|
|
}
|
|
configure->arch = enum_string(HA_LAST, sHostArch, un.machine);
|
|
configure->os = enum_string(HO_LAST, sHostOS, un.sysname);
|
|
configure->kernel = _detect_kernel(configure->os, un.release);
|
|
if(configure->prefs->flags & PREFS_v)
|
|
printf("Detected system %s version %s on %s\n",
|
|
sHostOS[configure->os],
|
|
sHostKernel[configure->kernel].version,
|
|
sHostArch[configure->arch]);
|
|
}
|
|
|
|
static HostKernel _detect_kernel(HostOS os, char const * release)
|
|
{
|
|
unsigned int i;
|
|
|
|
for(i = 0; i != HK_LAST; i++)
|
|
{
|
|
if(sHostKernel[i].os < os)
|
|
continue;
|
|
if(sHostKernel[i].os > os)
|
|
return HK_UNKNOWN;
|
|
if(strncmp(release, sHostKernel[i].version,
|
|
strlen(sHostKernel[i].version)) == 0)
|
|
return i;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
static int _load_subdirs(Prefs * prefs, char const * directory,
|
|
configArray * ca, String const * subdirs);
|
|
static int _configure_load(Prefs * prefs, String const * directory,
|
|
configArray * ca)
|
|
{
|
|
int ret = 0;
|
|
Config * config;
|
|
String * path;
|
|
String const * subdirs = NULL;
|
|
|
|
if((path = string_new(directory)) == NULL)
|
|
return configure_error(directory, 1);
|
|
if(string_append(&path, "/") != 0
|
|
|| string_append(&path, PROJECT_CONF) != 0
|
|
|| (config = config_new()) == NULL)
|
|
{
|
|
string_delete(path);
|
|
return configure_error(directory, 1);
|
|
}
|
|
config_set(config, "", "directory", directory);
|
|
if(prefs->flags & PREFS_v)
|
|
printf("%s%s%s", "Loading project file ", path, "\n");
|
|
if(config_load(config, path) != 0)
|
|
ret = configure_error(path, 1);
|
|
else
|
|
{
|
|
array_append(ca, &config);
|
|
subdirs = config_get(config, "", "subdirs");
|
|
}
|
|
string_delete(path);
|
|
if(subdirs == NULL)
|
|
return ret;
|
|
return _load_subdirs(prefs, directory, ca, subdirs);
|
|
}
|
|
|
|
static int _load_subdirs_subdir(Prefs * prefs, char const * directory,
|
|
configArray * ca, char const * subdir);
|
|
static int _load_subdirs(Prefs * prefs, char const * directory,
|
|
configArray * ca, String const * subdirs)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
char c;
|
|
String * subdir;
|
|
|
|
if((subdir = string_new(subdirs)) == NULL)
|
|
return 1;
|
|
for(i = 0; ret == 0; i++)
|
|
{
|
|
if(subdir[i] != ',' && subdir[i] != '\0')
|
|
continue;
|
|
c = subdir[i];
|
|
subdir[i] = '\0';
|
|
ret = _load_subdirs_subdir(prefs, directory, ca, subdir);
|
|
if(c == '\0')
|
|
break;
|
|
subdir[i] = c;
|
|
subdir += i + 1;
|
|
i = 0;
|
|
}
|
|
string_delete(subdir);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int _load_subdirs_subdir(Prefs * prefs, char const * directory,
|
|
configArray * ca, char const * subdir)
|
|
/* FIXME error checking */
|
|
{
|
|
int ret;
|
|
String * p;
|
|
|
|
p = string_new(directory);
|
|
string_append(&p, "/");
|
|
string_append(&p, subdir);
|
|
ret = _configure_load(prefs, p, ca);
|
|
string_delete(p);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int _configure_do(Configure * configure, configArray * ca)
|
|
{
|
|
size_t i;
|
|
size_t cnt = array_count(ca);
|
|
String const * di;
|
|
size_t j;
|
|
Config * cj;
|
|
String const * dj;
|
|
|
|
for(i = 0; i < cnt; i++)
|
|
{
|
|
array_get_copy(ca, i, &configure->config);
|
|
di = config_get(configure->config, "", "directory");
|
|
for(j = i; j < cnt; j++)
|
|
{
|
|
array_get_copy(ca, j, &cj);
|
|
dj = config_get(cj, "", "directory");
|
|
if(string_find(dj, di) == NULL)
|
|
break;
|
|
}
|
|
if(makefile(configure, di, ca, i, j) != 0)
|
|
break;
|
|
}
|
|
return (i == cnt) ? 0 : 1;
|
|
}
|
|
|
|
|
|
/* usage */
|
|
static void _prefs_init(Prefs * prefs);
|
|
static int _usage(void)
|
|
{
|
|
Prefs prefs;
|
|
|
|
_prefs_init(&prefs);
|
|
fprintf(stderr, "%s%s%s%s%s%s%s%s%s",
|
|
"Usage: configure [-nv][options...][directory]\n\
|
|
-n Do not actually write Makefiles\n\
|
|
-v Verbose mode\n\
|
|
-b Binary files directory (default: \"", prefs.bindir, "\")\n\
|
|
-d Destination prefix (default: \"\")\n\
|
|
-i Include files directory (default: \"", prefs.includedir, "\")\n\
|
|
-l Library files directory (default: \"", prefs.libdir, "\")\n\
|
|
-p Installation directory prefix (default: \"", prefs.prefix, "\")\n");
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* main */
|
|
int main(int argc, char * argv[])
|
|
{
|
|
Prefs prefs;
|
|
int o;
|
|
|
|
_prefs_init(&prefs);
|
|
while((o = getopt(argc, argv, "d:i:l:np:v")) != -1)
|
|
switch(o)
|
|
{
|
|
case 'b':
|
|
prefs.bindir = optarg;
|
|
break;
|
|
case 'd':
|
|
prefs.destdir = optarg;
|
|
break;
|
|
case 'i':
|
|
prefs.includedir = optarg;
|
|
break;
|
|
case 'l':
|
|
prefs.libdir = optarg;
|
|
break;
|
|
case 'n':
|
|
prefs.flags |= PREFS_n;
|
|
break;
|
|
case 'p':
|
|
prefs.prefix = optarg;
|
|
break;
|
|
case 'v':
|
|
prefs.flags |= PREFS_v;
|
|
break;
|
|
case '?':
|
|
return _usage();
|
|
}
|
|
if(argc - optind > 1)
|
|
return _usage();
|
|
return _configure(&prefs, argc - optind == 1 ? argv[argc - 1] : ".");
|
|
}
|
|
|
|
static void _prefs_init(Prefs * prefs)
|
|
{
|
|
struct stat st;
|
|
|
|
memset(prefs, 0, sizeof(Prefs));
|
|
prefs->destdir = "";
|
|
if(stat("/usr", &st) == 0) /* FIXME see below */
|
|
{
|
|
prefs->bindir = "bin";
|
|
prefs->includedir = "include";
|
|
prefs->libdir = "lib";
|
|
prefs->prefix = "/usr/local";
|
|
return;
|
|
}
|
|
prefs->bindir = "Binaries";
|
|
prefs->includedir = "Includes";
|
|
prefs->libdir = "Libraries";
|
|
prefs->prefix = "/Apps"; /* FIXME detect System or Apps/x first */
|
|
}
|