2020-08-08 15:47:34 +02:00
# 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 */
2021-05-21 10:36:50 +02:00
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 ) ;
}
2020-08-08 15:47:34 +02:00
/* 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 ) ;
2020-12-12 11:02:07 +01:00
/* add -I to the db too */
old = dbcflags ;
dbcflags = str_concat ( " " , " -I " , uprefix , " /include " , dbcflags , NULL ) ;
free ( old ) ;
2020-08-08 15:47:34 +02:00
old = rldflags ;
if ( ( rldflags ! = NULL ) & & ( * rldflags = = ' ^ ' ) ) {
rldflags + + ;
prfx = " ^ " ;
}
else
prfx = " " ;
rldflags = str_concat ( " " , prfx , " -L " , uprefix , " /lib " , rldflags , NULL ) ;
if ( old ! = ldflags ) free ( old ) ;
2020-12-12 11:02:07 +01:00
/* add -L to the db too */
old = dbldflags ;
dbldflags = str_concat ( " " , " -L " , uprefix , " /lib " , dbldflags , NULL ) ;
free ( old ) ;
2020-08-08 15:47:34 +02:00
}
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 ;
}