#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 */
/* load uincludes, uclfags, uldflags and uprefix - LOAD() inserts the u */
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);
old = rldflags;
if ((rldflags != NULL) && (*rldflags == '^')) {
rldflags++;
prfx = "^";
}
else
prfx = "";
rldflags = str_concat("", prfx, "-L", uprefix, "/lib ", rldflags, NULL);
if (old != ldflags) 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];
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;
}
printf("path='%s' fn='%s'\n", path, fn);
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;
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;
}