438 lines
12 KiB
C
438 lines
12 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "libs.h"
|
|
#include "log.h"
|
|
#include "db.h"
|
|
#include "dep.h"
|
|
|
|
/* Returns true if the first 2 characters of the output is OK */
|
|
static int try_icl_accept_ok(char *stdout_str)
|
|
{
|
|
return (strncmp(stdout_str, "OK", 2) == 0);
|
|
}
|
|
|
|
#define is_ctrl_prefix(ch) (((ch) == '!') || ((ch) == '^'))
|
|
|
|
static int try_icl__(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, const char *db_includes, const char *db_cflags, const char *db_ldflags, int run, int (*accept_res)(char *stdout_str))
|
|
{
|
|
char *out = NULL;
|
|
char *tmp, *inc;
|
|
const char *test_c;
|
|
char c[1024];
|
|
int l, compres;
|
|
|
|
if (includes != NULL) {
|
|
l = strlen(includes);
|
|
memcpy(c, includes, l);
|
|
c[l] = '\n';
|
|
l++;
|
|
strcpy(c+l, test_c_in);
|
|
test_c = c;
|
|
}
|
|
else
|
|
test_c = test_c_in;
|
|
|
|
logprintf(logdepth, "trying '%s' and '%s' and '%s', %s\n", str_null(db_includes), str_null(db_cflags), str_null(db_ldflags), run ? "with a run" : "with no run");
|
|
|
|
if (run)
|
|
compres = compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out);
|
|
else {
|
|
char *fn_output = NULL;
|
|
compres = compile_code(logdepth+1, test_c, &fn_output, NULL, cflags, ldflags);
|
|
if (fn_output != NULL) {
|
|
unlink(fn_output);
|
|
free(fn_output);
|
|
}
|
|
}
|
|
|
|
|
|
if (compres == 0) {
|
|
if (!run || target_emu_fail(out) || accept_res(out)) {
|
|
free(out);
|
|
|
|
/* no prefix: don't modify the database, the caller will do that */
|
|
if (prefix == NULL)
|
|
return 1;
|
|
|
|
tmp = malloc(strlen(prefix) + 32);
|
|
|
|
if ((db_includes == NULL) || (*db_includes == '\0'))
|
|
inc = strclone("");
|
|
else
|
|
inc = uniq_inc_str(db_includes, NULL, "\\n", 0, 0, NULL);
|
|
sprintf(tmp, "%s/includes", prefix);
|
|
put(tmp, inc);
|
|
|
|
if (db_cflags == NULL)
|
|
db_cflags = "";
|
|
|
|
sprintf(tmp, "%s/cflags", prefix);
|
|
put(tmp, db_cflags);
|
|
|
|
|
|
if (db_ldflags == NULL)
|
|
db_ldflags = "";
|
|
sprintf(tmp, "%s/ldflags", prefix);
|
|
put(tmp, db_ldflags);
|
|
|
|
if (inc != NULL) {
|
|
report("OK ('%s', '%s' and '%s')\n", str_null(inc), str_null(db_cflags), str_null(db_ldflags));
|
|
free(inc);
|
|
}
|
|
else
|
|
report("OK ('%s' and '%s')\n", str_null(db_cflags), str_null(db_ldflags));
|
|
|
|
sprintf(tmp, "%s/presents", prefix);
|
|
put(tmp, strue);
|
|
free(tmp);
|
|
return 1;
|
|
}
|
|
free(out);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define LOAD(node) \
|
|
do { \
|
|
if (u ## node != NULL) break; \
|
|
strcpy(apath_end, #node); \
|
|
u ## node = get(apath); \
|
|
} while(0)
|
|
|
|
#define SET(dst, src, is_flag) \
|
|
do { \
|
|
char *__sep__ = is_flag ? " " : "\n"; \
|
|
const char *__dst__ = dst == NULL ? "" : dst; \
|
|
char *__out__; \
|
|
if (is_ctrl_prefix(*__dst__)) __dst__++; \
|
|
if (*src == '!') \
|
|
__out__ = strclone(src+1); \
|
|
else if (*src == '^') {\
|
|
if (src[1] != '\0') \
|
|
__out__ = str_concat("", src+1, __sep__, __dst__, NULL); \
|
|
else \
|
|
__out__ = strclone(__dst__); \
|
|
} \
|
|
else { \
|
|
if (*__dst__ != '\0') \
|
|
__out__ = str_concat("", __dst__, __sep__, src, NULL); \
|
|
else \
|
|
__out__ = strclone(src); \
|
|
} \
|
|
free(dst); \
|
|
dst = __out__; \
|
|
if (is_flag) { \
|
|
char *__s__; \
|
|
for(__s__ = dst; *__s__ != '\0'; __s__++) \
|
|
if ((*__s__ == '\n') || (*__s__ == '\r')) \
|
|
*__s__ = ' '; \
|
|
} \
|
|
} while(0)
|
|
|
|
|
|
/* Figure user overrides and call try_icl__() accordingly */
|
|
int try_icl_(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, int run, int (*accept_res)(char *stdout_str))
|
|
{
|
|
char apath[1024], *apath_end;
|
|
int l, res;
|
|
const char *uincludes = NULL, *ucflags = NULL, *uldflags = NULL, *uprefix = NULL; /* user specified */
|
|
char *rincludes, *rcflags, *rldflags; /* real */
|
|
char *dbincludes = NULL, *dbcflags = NULL, *dbldflags = NULL; /* what to add in the db at the end */
|
|
|
|
if ((prefix == NULL) ? 0 : strlen(prefix) + strlen(db_cwd) > sizeof(apath)-32) {
|
|
report("ERROR: no room for try_icl_() - prefix is probably too long.\n");
|
|
return -1;
|
|
}
|
|
|
|
/* load uincludes, uclfags, uldflags and uprefix - LOAD() inserts the u */
|
|
if (prefix != NULL) { /* prefix == NULL means non-standard icl; caller sets non-standard nodes, the user can't affect that */
|
|
l = sprintf(apath, "/arg/icl/%s/", prefix); apath_end = apath+l;
|
|
LOAD(includes);
|
|
LOAD(cflags);
|
|
LOAD(ldflags);
|
|
LOAD(prefix);
|
|
l = sprintf(apath, "/arg/icl/%s/%s/", db_cwd, prefix); apath_end = apath+l;
|
|
LOAD(includes);
|
|
LOAD(cflags);
|
|
LOAD(ldflags);
|
|
LOAD(prefix);
|
|
}
|
|
|
|
/* special case: all three specified by the user - ignore what the detector wanted, but run only once per node prefix */
|
|
if ((uincludes != NULL) && (ucflags != NULL) && (uldflags != NULL)) {
|
|
const char *am;
|
|
sprintf(apath, "%s/icl/all_manual_result", prefix);
|
|
am = get(apath);
|
|
if (am != NULL)
|
|
return istrue(am); /* return cached result if available */
|
|
res = try_icl__(logdepth, prefix, test_c_in, uincludes, ucflags, uldflags, uincludes, ucflags, uldflags, run, accept_res);
|
|
put(apath, res ? strue : sfalse);
|
|
return res;
|
|
}
|
|
|
|
/* TODO: get default cflags here */
|
|
rincludes = NULL;
|
|
rcflags = strclone(get("cc/cflags"));
|
|
rldflags = strclone(get("cc/ldflags"));
|
|
|
|
/* override base/default values with detection requested ones */
|
|
if (includes != NULL) SET(rincludes, includes, 0);
|
|
if (cflags != NULL) SET(rcflags, cflags, 1);
|
|
if (ldflags != NULL) SET(rldflags, ldflags, 1);
|
|
|
|
if (includes != NULL) SET(dbincludes, includes, 0);
|
|
if (cflags != NULL) SET(dbcflags, cflags, 1);
|
|
if (ldflags != NULL) SET(dbldflags, ldflags, 1);
|
|
|
|
/* override detection with user specified ICL values */
|
|
if (uincludes != NULL) SET(rincludes, uincludes, 0);
|
|
if (ucflags != NULL) SET(rcflags, ucflags, 1);
|
|
if (uldflags != NULL) SET(rldflags, uldflags, 1);
|
|
|
|
if (uincludes != NULL) SET(dbincludes, uincludes, 0);
|
|
if (ucflags != NULL) SET(dbcflags, ucflags, 1);
|
|
if (uldflags != NULL) SET(dbldflags, uldflags, 1);
|
|
|
|
/* insert prefix as needed */
|
|
if (uprefix != NULL) {
|
|
char *old, *prfx;
|
|
|
|
old = rcflags;
|
|
if ((rcflags != NULL) && (*rcflags == '^')) {
|
|
rcflags++;
|
|
prfx = "^";
|
|
}
|
|
else
|
|
prfx = "";
|
|
rcflags = str_concat("", prfx, "-I", uprefix, "/include ", rcflags, NULL);
|
|
if (old != cflags) free(old);
|
|
|
|
/* add -I to the db too */
|
|
old = dbcflags;
|
|
dbcflags = str_concat("", "-I", uprefix, "/include ", dbcflags, NULL);
|
|
free(old);
|
|
|
|
|
|
old = rldflags;
|
|
if ((rldflags != NULL) && (*rldflags == '^')) {
|
|
rldflags++;
|
|
prfx = "^";
|
|
}
|
|
else
|
|
prfx = "";
|
|
rldflags = str_concat("", prfx, "-L", uprefix, "/lib ", rldflags, NULL);
|
|
if (old != ldflags) free(old);
|
|
|
|
/* add -L to the db too */
|
|
old = dbldflags;
|
|
dbldflags = str_concat("", "-L", uprefix, "/lib ", dbldflags, NULL);
|
|
free(old);
|
|
}
|
|
|
|
res = try_icl__(logdepth, prefix, test_c_in, rincludes, rcflags, rldflags, dbincludes, dbcflags, dbldflags, run, accept_res);
|
|
|
|
/* if we had to alloc, free here */
|
|
free(rincludes);
|
|
free(rcflags);
|
|
free(rldflags);
|
|
free(dbincludes);
|
|
free(dbcflags);
|
|
free(dbldflags);
|
|
|
|
return res;
|
|
}
|
|
|
|
#undef LOAD
|
|
#undef SET
|
|
|
|
int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
|
|
{
|
|
return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 1, try_icl_accept_ok);
|
|
}
|
|
|
|
int try_icl_with_deps(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, const char *dep_includes, const char *dep_cflags, const char *dep_ldflags, int run)
|
|
{
|
|
int res;
|
|
|
|
if ((dep_includes != NULL) && (*dep_includes == '\0')) dep_includes = NULL;
|
|
if ((dep_cflags != NULL) && (*dep_cflags == '\0')) dep_cflags = NULL;
|
|
if ((dep_ldflags != NULL) && (*dep_ldflags == '\0')) dep_ldflags = NULL;
|
|
|
|
if (dep_includes != NULL) includes = str_concat(" ", dep_includes, includes, NULL);
|
|
if (dep_cflags != NULL) cflags = str_concat(" ", dep_cflags, cflags, NULL);
|
|
if (dep_ldflags != NULL) ldflags = str_concat(" ", dep_ldflags, ldflags, NULL);
|
|
|
|
res = try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, run, try_icl_accept_ok);
|
|
|
|
if (dep_includes != NULL) free((char *)includes);
|
|
if (dep_cflags != NULL) free((char *)cflags);
|
|
if (dep_ldflags != NULL) free((char *)ldflags);
|
|
|
|
return res;
|
|
}
|
|
|
|
int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
|
|
{
|
|
return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 0, try_icl_accept_ok);
|
|
}
|
|
|
|
|
|
int try_fail(int logdepth, const char *prefix)
|
|
{
|
|
char *tmp;
|
|
tmp = malloc(strlen(prefix) + 32);
|
|
sprintf(tmp, "%s/presents", prefix);
|
|
put(tmp, sfalse);
|
|
free(tmp);
|
|
report("not found\n");
|
|
logprintf(logdepth, "NOT FOUND.");
|
|
return 1;
|
|
}
|
|
|
|
static int try_pkg_config_(int logdepth, char *pkgname, const char *prefix, const char *test_c)
|
|
{
|
|
char *cflags, *ldflags;
|
|
int res;
|
|
|
|
logprintf(logdepth, "Trying pkg-config %s\n", pkgname);
|
|
if (run_pkg_config(logdepth+1, pkgname, &cflags, &ldflags) == 0)
|
|
res = try_icl(logdepth+1, prefix, test_c, NULL, cflags, ldflags);
|
|
else
|
|
res = 0;
|
|
free(cflags);
|
|
free(ldflags);
|
|
|
|
return res;
|
|
}
|
|
|
|
int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat, const char *reqver)
|
|
{
|
|
char **pkg_ver, **s;
|
|
int num_pkg_ver;
|
|
int res = 0;
|
|
(void) includes; /* not used */
|
|
|
|
run_pkg_config_lst(logdepth, pkgpat, &num_pkg_ver, &pkg_ver);
|
|
if (pkg_ver == NULL)
|
|
return 0;
|
|
|
|
if (reqver != NULL) {
|
|
/* search the list for the preferred version */
|
|
for(s = pkg_ver; *s != NULL; s+=2) {
|
|
if (strcmp(s[1], reqver) == 0) {
|
|
if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
|
|
res = 1;
|
|
report("Found version required (%s) using pkg_config.\n", reqver);
|
|
goto out;
|
|
}
|
|
else {
|
|
report("The version required (%s) is found (via pkg_config) but does not work\n", reqver);
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
for(s = pkg_ver; *s != NULL; s+=2) {
|
|
if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
|
|
res = 1;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:;
|
|
filelist_free(&num_pkg_ver, &pkg_ver);
|
|
return res;
|
|
}
|
|
|
|
|
|
int import_icl(const char *key, const char *fn)
|
|
{
|
|
char path[1024];
|
|
|
|
if (strlen(key) > sizeof(path)-32) {
|
|
report("ERROR: no room for import_icl() - key is probably too long.\n");
|
|
return -1;
|
|
}
|
|
|
|
switch(*key) {
|
|
case 'l': sprintf(path, "/arg/icl/%s/ldflags", key+8); break;
|
|
case 'c': sprintf(path, "/arg/icl/%s/cflags", key+7); break;
|
|
case 'i': sprintf(path, "/arg/icl/%s/includes", key+9); break;
|
|
case 'p': sprintf(path, "/arg/icl/%s/prefix", key+7); break;
|
|
default:
|
|
return 1;
|
|
}
|
|
return put(path, fn) == NULL;
|
|
}
|
|
|
|
|
|
static long field_accept_len;
|
|
static int field_accept_res(char *stdout_str)
|
|
{
|
|
char *end;
|
|
field_accept_len = strtol(stdout_str, &end, 10);
|
|
if (((*end == '\0') || (*end == '\r') || (*end == '\n')) && (field_accept_len > 0))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int try_icl_sfield(int logdepth, const char *prefix, const char *structn, const char *fieldn, const char *includes, const char *cflags, const char *ldflags)
|
|
{
|
|
int res;
|
|
char test_c[512];
|
|
char ls[16];
|
|
const char *test_c_in =
|
|
NL "#include <stdio.h>"
|
|
NL "int main()"
|
|
NL "{"
|
|
NL " %s s;"
|
|
NL " printf(\"%%ld\\n\", (long)sizeof(s.%s));"
|
|
NL "}"
|
|
NL;
|
|
|
|
if (strlen(fieldn) + strlen(structn) + strlen(test_c_in) + 32 >= sizeof(test_c)) {
|
|
report("ERROR: no room for try_icl_sfield() - struct or field name is probably too long.\n");
|
|
return -1;
|
|
}
|
|
|
|
sprintf(test_c, test_c_in, structn, fieldn);
|
|
|
|
res = try_icl_(logdepth, prefix, test_c, includes, cflags, ldflags, 1, field_accept_res);
|
|
if (res) {
|
|
sprintf(test_c, "%s/sizeof", prefix);
|
|
sprintf(ls, "%ld", field_accept_len);
|
|
put(test_c, ls);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int try_icl_sfields(int logdepth, const char *prefix, const char *structn, const char **fields, const char *includes, const char *cflags, const char *ldflags, int silent_exit_first_fail)
|
|
{
|
|
int succ = 0, first = 1;
|
|
require("cc/cc", logdepth, 1);
|
|
|
|
for(; *fields != NULL; fields++) {
|
|
report("Checking for %s.%s... ", structn, *fields);
|
|
logprintf(logdepth, "%s: checking for field %s...\n", structn, *fields);
|
|
|
|
logdepth++;
|
|
if (try_icl_sfield(logdepth, prefix, structn, *fields, includes, cflags, ldflags)) {
|
|
succ = 1;
|
|
}
|
|
else if ((silent_exit_first_fail) && (first)) {
|
|
return 1;
|
|
}
|
|
logdepth--;
|
|
first = 0;
|
|
}
|
|
|
|
|
|
if (!succ)
|
|
try_fail(logdepth, "libs/fsmount/next_dev");
|
|
|
|
return 0;
|
|
}
|