1235 lines
31 KiB
C++
1235 lines
31 KiB
C++
/**
|
||
* Part of the Lccrt Project, under the Apache License v2.0
|
||
* See http://www.apache.org/licenses/LICENSE-2.0.txt for license information.
|
||
* SPDX-License-Identifier: Apache-2.0
|
||
*
|
||
* lcbe - библиотека динамической компиляции.
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <assert.h>
|
||
#include <errno.h>
|
||
#include <dlfcn.h>
|
||
#include <ctype.h>
|
||
#include <libgen.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/types.h>
|
||
#include <sys/wait.h>
|
||
#include <sys/socket.h>
|
||
|
||
#include "lcbe_real.h"
|
||
|
||
#define lcbe_str_eq( a, b) (strcmp( a, b) == 0)
|
||
#define lcbe_assign( a, b) ((a) ? (*(a) = (b)) : 0)
|
||
#define lcbe_max( a, b) ((a) > (b) ? (a) : (b))
|
||
|
||
extern "C" int LCCRT_ASM_FUNC_COMPILE( lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf);
|
||
extern "C" const char *LCCRT_ASM_FUNC_GETTOOL( const char *targ, const char *type, const char *name);
|
||
|
||
const char *LCCRT_PLUGIN_LCCRT_VERSION = LCCRT_VERSION;
|
||
const char *LCCRT_PLUGIN_LIBRARY_NAME = "lcbe";
|
||
const char *LCCRT_PLUGIN_TARGETS[] = {"e2k64", "x86_64", 0};
|
||
|
||
static void lcbe_init( void) __attribute__((constructor));
|
||
static void lcbe_done( void) __attribute__((destructor));
|
||
|
||
/**
|
||
* Внешние утилиты.
|
||
*/
|
||
typedef struct
|
||
{
|
||
char *gcc_path; /* путь установки программы gcc */
|
||
char *gcc; /* компилятор */
|
||
char *include_path; /* путь до стандартной директории include */
|
||
char *include_cpp_stl_path; /* путь до стандартной директории include/c++/stl */
|
||
char *ld_path; /* путь до программы линковщик */
|
||
char *ld; /* линковщик */
|
||
char *as_path; /* путь до программы ассемблер */
|
||
char *as; /* ассемблер */
|
||
char *lib32_path; /* путь до 32-битных библиотек компилятора */
|
||
char *lib64_path; /* путь до 32-битных библиотек компилятора */
|
||
char *gcc_base_path; /* путь до системных файлов компилятора */
|
||
char *gcc_lib32_path; /* путь до 32-битных системных библиотек компилятора */
|
||
char *gcc_lib64_path; /* путь до 64-битных системных библиотек компилятора */
|
||
char *bd; /* путь до директории с утилитами (binutils) */
|
||
char *fs; /* путь до системной директории */
|
||
} lcbe_tools_t;
|
||
|
||
/**
|
||
* Настройки оптимизирующего бекэнда.
|
||
*/
|
||
typedef struct
|
||
{
|
||
int verbose; /* флаг информационного режима */
|
||
const char *save_temps; /* флаг сохранения временных файлов */
|
||
char *cc_flags; /* дополнительные флаги компиляции */
|
||
int8_t is_dbg; /* флаг создания отладочных dwarf-структур */
|
||
char *lcbe_cc_config; /* внешняя программа вычисления конфигурации */
|
||
char *lcbe_home; /* home-директория библиотеки */
|
||
char *lcbe_conf; /* конфигурационный файл библиотеки */
|
||
} lcbe_config_t;
|
||
|
||
/**
|
||
* Глобальные данные библиотеки.
|
||
*/
|
||
typedef struct
|
||
{
|
||
lcbe_tools_t tools; /* внешние утилиты */
|
||
lcbe_config_t conf; /* настройки оптимизирующего бекэнда */
|
||
} lcbe_info_t;
|
||
|
||
/**
|
||
* Данные потока компиляции.
|
||
*/
|
||
typedef struct
|
||
{
|
||
lcbe_info_t *info; /* ссылка на глобальные данные библиотеки */
|
||
lccrt_asm_compile_config_t *aci;
|
||
lccrt_module_ptr m;
|
||
char *tmp_dir; /* директория для размещения временных файлов */
|
||
char *out_name; /* название выходного файла */
|
||
char *src_name; /* название файла с Си-кодом */
|
||
int8_t is_obj;
|
||
int8_t save_temps; /* флаг сохранения временных файлов */
|
||
int ofd; /* дескриптор выходного файла */
|
||
} lcbe_compile_t;
|
||
|
||
/**
|
||
* Глобальные данные потока компиляции.
|
||
*/
|
||
static __thread lcbe_compile_t lcbe_comp = {0};
|
||
|
||
/**
|
||
* Глобальные данные библиотеки.
|
||
*/
|
||
static lcbe_info_t lcbe_info = {{0}};
|
||
|
||
/**
|
||
* Проверка на установку опции.
|
||
*/
|
||
static int
|
||
lcbe_is_option( const char *opt,
|
||
int default_value)
|
||
{
|
||
int result = default_value;
|
||
const char *v = getenv( opt);
|
||
|
||
if ( v )
|
||
{
|
||
if ( (strcmp( v, "yes") == 0)
|
||
|| (strcmp( v, "YES") == 0)
|
||
|| (strcmp( v, "on") == 0)
|
||
|| (strcmp( v, "ON") == 0)
|
||
|| (strcmp( v, "enable") == 0)
|
||
|| (strcmp( v, "ENABLE") == 0)
|
||
|| (strcmp( v, "1") == 0) )
|
||
{
|
||
result = 1;
|
||
} else
|
||
{
|
||
result = 0;
|
||
}
|
||
}
|
||
|
||
return (result);
|
||
} /* lcbe_is_option */
|
||
|
||
/**
|
||
* Чтение опции.
|
||
*/
|
||
static char *
|
||
lcbe_get_option( const char *opt,
|
||
const char *default_value)
|
||
{
|
||
char *result = (char *)default_value;
|
||
char *v = getenv( opt);
|
||
|
||
if ( v )
|
||
{
|
||
result = v;
|
||
}
|
||
|
||
if ( result )
|
||
{
|
||
result = strdup( result);
|
||
}
|
||
|
||
return (result);
|
||
} /* lcbe_get_option */
|
||
|
||
/**
|
||
* Ожидание завершения дочернего процесса с возвратом кода завершения.
|
||
*/
|
||
static int
|
||
lcbe_waitpid( pid_t pid)
|
||
{
|
||
int r = -1;
|
||
int state = -1;
|
||
|
||
if ( (pid > 0) )
|
||
{
|
||
pid_t wpid = waitpid( pid, &state, 0);
|
||
|
||
if ( (wpid != pid)
|
||
|| !WIFEXITED( state)
|
||
|| (WEXITSTATUS( state) != 0) )
|
||
{
|
||
r = WEXITSTATUS( state) ? WEXITSTATUS( state) : -1;
|
||
} else
|
||
{
|
||
r = 0;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_waitpid */
|
||
|
||
/**
|
||
* Подготовка аргументов для компиляции модуля.
|
||
*/
|
||
static int
|
||
lcbe_compile_module_args_init( lcbe_compile_t *l, char *argv[50])
|
||
{
|
||
char b[4096];
|
||
int k = 0;
|
||
lcbe_config_t *c = &(l->info->conf);
|
||
|
||
//argv[k] = strdup( "lccrt"); k++;
|
||
argv[k] = strdup( l->src_name); k++;
|
||
argv[k] = strdup( "-O1"); k++;
|
||
argv[k] = strdup( "-fexceptions"); k++;
|
||
//argv[k] = strdup( "--mcpu-internal=elbrus-v2"); k++;
|
||
if ( (l->aci->is_pic == 0) )
|
||
{
|
||
if ( (l->aci->pie_level == 0) )
|
||
{
|
||
argv[k] = strdup( "-fPIC"); k++;
|
||
|
||
} else if ( (l->aci->pie_level == 1) )
|
||
{
|
||
argv[k] = strdup( "-fpie"); k++;
|
||
|
||
} else if ( (l->aci->pie_level == 2) )
|
||
{
|
||
argv[k] = strdup( "-fPIE"); k++;
|
||
} else
|
||
{
|
||
assert( 0);
|
||
}
|
||
} else
|
||
{
|
||
assert( l->aci->pie_level == 0);
|
||
}
|
||
if ( l->aci->function_sections )
|
||
{
|
||
argv[k] = strdup( "-ffunction-sections"); k++;
|
||
}
|
||
if ( l->aci->data_sections )
|
||
{
|
||
argv[k] = strdup( "-fdata-sections"); k++;
|
||
}
|
||
if ( 1 || (l->aci->dbg_level > 0) )
|
||
{
|
||
argv[k] = strdup( "-g"); k++;
|
||
c->is_dbg = 1;
|
||
}
|
||
argv[k] = strdup( l->is_obj ? "-c" : "-S"); k++;
|
||
argv[k] = strdup( "-o"); k++;
|
||
argv[k] = strdup( l->out_name); k++;
|
||
if ( c->cc_flags )
|
||
{
|
||
int j = 0;
|
||
char *p = c->cc_flags + 0;
|
||
|
||
while ( p[j]
|
||
&& (k < 50) )
|
||
{
|
||
while ( p[j]
|
||
&& (p[j] == ' ') )
|
||
{
|
||
j++;
|
||
}
|
||
|
||
if ( p[j] )
|
||
{
|
||
int h = 0;
|
||
|
||
while ( p[j+h]
|
||
&& (p[j+h] != ' ') )
|
||
{
|
||
h++;
|
||
}
|
||
|
||
argv[k] = strndup( p + j, h); k++;
|
||
j += h;
|
||
}
|
||
}
|
||
}
|
||
|
||
argv[k] = 0;
|
||
assert( k < 50);
|
||
|
||
return (k);
|
||
} /* lcbe_compile_module_args_init */
|
||
|
||
/**
|
||
* Компиляция модуля до ассемблерного файла.
|
||
*/
|
||
static int
|
||
lcbe_compile_module( lcbe_compile_t *l)
|
||
{
|
||
char data[4096];
|
||
int i;
|
||
int r = 0;
|
||
int k = 0;
|
||
int read_count = 0;
|
||
int write_count = 0;
|
||
int argc = 0;
|
||
FILE *f = 0;
|
||
char *argv[50] = {0};
|
||
|
||
/* Преобразуем представление модуля в Си-код. */
|
||
lcbe_emit_c( l->m, l->src_name);
|
||
|
||
/* Подготовка задачи компиляции. */
|
||
argc = lcbe_compile_module_args_init( l, argv);
|
||
k += snprintf( data + k, lcbe_max( 0, 4096 - k), "gcc");
|
||
for ( i = 0; i < argc; ++i )
|
||
{
|
||
k += snprintf( data + k, lcbe_max( 0, 4096 - k), " %s", argv[i]);
|
||
free( argv[i]);
|
||
}
|
||
|
||
if ( (k >= 4096) )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
/* Выполнение задачи компиляции. */
|
||
if ( l->info->conf.verbose )
|
||
{
|
||
printf( "COMPILE: %s\n", data);
|
||
}
|
||
|
||
if ( (system( data) != 0) )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
/* Передача результирующего файла в выходной файловой поток. */
|
||
f = fopen( l->out_name, "r");
|
||
if ( !f )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
while ( !feof( f) )
|
||
{
|
||
int n = fread( data, 1, 4096, f);
|
||
|
||
if ( (n < 0) )
|
||
{
|
||
fclose( f);
|
||
return (-1);
|
||
|
||
} else if ( (n > 0) )
|
||
{
|
||
l->aci->write( l->aci->write_info, data, n);
|
||
}
|
||
}
|
||
|
||
fclose( f);
|
||
|
||
return (r);
|
||
} /* lcbe_compile_module */
|
||
|
||
/**
|
||
* Подготовка к работе.
|
||
*/
|
||
static int
|
||
lcbe_compile_module_init( lcbe_compile_t *l, lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf)
|
||
{
|
||
char s[1024];
|
||
int r = 0;
|
||
int sl = 0;
|
||
int sfd = -1;
|
||
unsigned mode = 0;
|
||
|
||
memset( l, 0, sizeof( l[0]));
|
||
l->info = &lcbe_info;
|
||
l->m = m;
|
||
l->aci = cnf;
|
||
l->ofd = -1;
|
||
l->out_name = 0;
|
||
l->src_name = 0;
|
||
|
||
if ( getenv( "LCBE_TMP") )
|
||
{
|
||
l->tmp_dir = strdup( getenv( "LCBE_TMP"));
|
||
} else
|
||
{
|
||
l->tmp_dir = strdup( "/tmp/lcbe");
|
||
}
|
||
|
||
if ( getenv( "LCBE_SAVE") )
|
||
{
|
||
l->save_temps = atoi( getenv( "LCBE_SAVE"));
|
||
}
|
||
|
||
if ( lcbe_str_eq( cnf->out_type, "asm") )
|
||
{
|
||
l->is_obj = 0;
|
||
|
||
} else if ( lcbe_str_eq( cnf->out_type, "obj") )
|
||
{
|
||
l->is_obj = 1;
|
||
} else
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
sl = snprintf( s, 1024, "mkdir -p -m a+rwx %s", l->tmp_dir);
|
||
if ( (sl >= 1024)
|
||
|| (system( s) != 0) )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
mode |= S_IRWXU;
|
||
mode |= S_IRWXG;
|
||
mode |= S_IRWXO;
|
||
sl = snprintf( s, 1024, "%s/%d.XXXXXX.%s", l->tmp_dir, getpid(), l->is_obj ? "o" : "s");
|
||
if ( (sl >= 1024) )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
l->out_name = strdup( s);
|
||
l->ofd = mkostemps( l->out_name, 2, mode);
|
||
if ( (l->ofd < 0) )
|
||
{
|
||
return (-1);
|
||
}
|
||
|
||
l->src_name = strdup( l->out_name);
|
||
l->src_name[sl - 1] = 'c';
|
||
#if 0
|
||
sfd = mkostemps( l->src_name, 2, mode);
|
||
if ( (sfd < 0) )
|
||
{
|
||
return (-1);
|
||
} else
|
||
{
|
||
close( sfd);
|
||
}
|
||
#endif
|
||
|
||
return (0);
|
||
} /* lcbe_compile_module_init */
|
||
|
||
/**
|
||
* Завершение работы.
|
||
*/
|
||
static int
|
||
lcbe_compile_module_done( lcbe_compile_t *l)
|
||
{
|
||
int r = 0;
|
||
|
||
if ( (l->ofd >= 0) )
|
||
{
|
||
close( l->ofd);
|
||
if ( !l->save_temps )
|
||
{
|
||
unlink( l->out_name);
|
||
}
|
||
}
|
||
|
||
if ( l->out_name )
|
||
{
|
||
free( l->out_name);
|
||
}
|
||
|
||
if ( l->src_name )
|
||
{
|
||
if ( !l->save_temps )
|
||
{
|
||
unlink( l->src_name);
|
||
}
|
||
|
||
free( l->src_name);
|
||
}
|
||
|
||
if ( l->tmp_dir )
|
||
{
|
||
free( l->tmp_dir);
|
||
}
|
||
|
||
memset( l, 0, sizeof( l[0]));
|
||
|
||
l->ofd = -1;
|
||
|
||
return (r);
|
||
} /* lcbe_compile_module_done */
|
||
|
||
/**
|
||
* Компиляция модуля до ассемблерного файла.
|
||
*/
|
||
int
|
||
LCCRT_ASM_FUNC_COMPILE( lccrt_module_ptr m,
|
||
lccrt_asm_compile_config_t *cnf)
|
||
{
|
||
int r = -1;
|
||
lcbe_compile_t *l = &lcbe_comp;
|
||
|
||
if ( (lcbe_compile_module_init( l, m, cnf) == 0)
|
||
&& (lcbe_compile_module( l) == 0) )
|
||
{
|
||
r = 0;
|
||
}
|
||
|
||
if ( (lcbe_compile_module_done( l) != 0) )
|
||
{
|
||
r = -1;
|
||
}
|
||
|
||
return (r);
|
||
} /* LCCRT_ASM_FUNC_COMPILE */
|
||
|
||
/**
|
||
* Старт внешней программы с перенаправлением стандартного потока вывода
|
||
* на канальный файловый дескриптор. При успешном запуске возвращается
|
||
* файловый дескриптор, доступный на чтение, с выводом внешней программы
|
||
* и номер процесса с внешней программой (wpid) для проверки успешного
|
||
* выполнения внешней программы (см. lcbe_waitpid).
|
||
*/
|
||
static int
|
||
lcbe_exec_open( pid_t *wpid,
|
||
const char *path, /* первый аргумент execv */
|
||
char *argv[]) /* второй аргумент execv */
|
||
{
|
||
pid_t pid;
|
||
int fd[2] = {-1, -1};
|
||
int r = -1;
|
||
|
||
lcbe_assign( wpid, -1);
|
||
|
||
if ( (pipe( fd) != 0) )
|
||
{
|
||
/* Не удалось создать канал. */
|
||
return (r);
|
||
}
|
||
|
||
pid = fork();
|
||
if ( (pid < 0) )
|
||
{
|
||
/* Не удалось создать процесс. */
|
||
return (r);
|
||
}
|
||
|
||
if ( (pid == 0) )
|
||
{
|
||
/* Запускаем внешнюю программу. */
|
||
close( fd[0]);
|
||
dup2( fd[1], STDOUT_FILENO);
|
||
dup2( fd[1], STDERR_FILENO);
|
||
close( fd[1]);
|
||
execvp( path, argv);
|
||
} else
|
||
{
|
||
/* Возвращаем файловый дескриптор с выводом внешней программы. */
|
||
close( fd[1]);
|
||
r = fd[0];
|
||
if ( wpid )
|
||
{
|
||
(*wpid) = pid;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_exec_open */
|
||
|
||
/**
|
||
* Удаление старого значения и возврат копии нового значения, либо сохранение
|
||
* старого значения, если новое значение равно 0.
|
||
*/
|
||
static char *
|
||
lcbe_reinit_str( char *old_value,
|
||
const char *new_value)
|
||
{
|
||
char *r = old_value;
|
||
|
||
if ( new_value )
|
||
{
|
||
r = strdup( new_value);
|
||
if ( old_value )
|
||
{
|
||
free( old_value);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_reinit_str */
|
||
|
||
/**
|
||
* Возврат конкатенация строк a и b с удалением строки a.
|
||
*/
|
||
static char *
|
||
lcbe_concat_str_by( char *a,
|
||
const char *b)
|
||
{
|
||
char *r = 0;
|
||
|
||
if ( !a )
|
||
{
|
||
r = strdup( b);
|
||
} else
|
||
{
|
||
int la = strlen( a);
|
||
int lb = strlen( b);
|
||
|
||
r = (char *)malloc( la + lb + 1);
|
||
strcpy( r, a);
|
||
strcpy( r + la, b);
|
||
free( a);
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_concat_str_by */
|
||
|
||
/**
|
||
* Возврат количества пробельных символов с начала строки (без учета перевода строки).
|
||
*/
|
||
static int
|
||
lcbe_skip_space( const char *s)
|
||
{
|
||
int k = 0;
|
||
|
||
while ( s[k]
|
||
&& isspace( s[k])
|
||
&& (s[k] != '\n') )
|
||
{
|
||
k++;
|
||
}
|
||
|
||
return (k);
|
||
} /* lcbe_skip_space */
|
||
|
||
/**
|
||
* Возврат количества непробельных символов в начале строки.
|
||
*/
|
||
static int
|
||
lcbe_skip_str( const char *s)
|
||
{
|
||
int k = 0;
|
||
|
||
while ( s[k]
|
||
&& !isspace( s[k])
|
||
&& (s[k] != '\n') )
|
||
{
|
||
k++;
|
||
}
|
||
|
||
return (k);
|
||
} /* lcbe_skip_str */
|
||
|
||
/**
|
||
* Чтение из файлового потока значений переменных.
|
||
*/
|
||
static int
|
||
lcbe_read_block( int fd,
|
||
char *block,
|
||
int size)
|
||
{
|
||
int n;
|
||
int is_work = 1;
|
||
|
||
n = 0;
|
||
while ( is_work )
|
||
{
|
||
int l = read( fd, block + n, size - n);
|
||
|
||
is_work = (l > 0);
|
||
n += l;
|
||
}
|
||
|
||
return (n);
|
||
} /* lcbe_read_block */
|
||
|
||
/**
|
||
* Исполнение внешней команды с записью выходного потока.
|
||
*/
|
||
static int
|
||
lcbe_get_exec_result( const char *cmd, char **argv, int max_len, char res[])
|
||
{
|
||
int n = 0;
|
||
int fd = -1;
|
||
pid_t pid = -1;
|
||
|
||
if ( res )
|
||
{
|
||
res[0] = 0;
|
||
}
|
||
|
||
fd = lcbe_exec_open( &pid, cmd, argv);
|
||
if ( (fd < 0) )
|
||
{
|
||
assert( 0);
|
||
return (0);
|
||
}
|
||
|
||
if ( res )
|
||
{
|
||
n = lcbe_read_block( fd, res, max_len);
|
||
res[n] = 0;
|
||
if ( (n > 0)
|
||
&& (res[n-1] == '\n') )
|
||
{
|
||
res[n-1] = 0;
|
||
}
|
||
}
|
||
|
||
if ( (lcbe_waitpid( pid) != 0) )
|
||
{
|
||
int k = 0;
|
||
|
||
fprintf( stderr, "Can't execute programm [%s] with arguments:", cmd);
|
||
while ( argv[k] )
|
||
{
|
||
fprintf( stderr, " [%s]", argv[k]);
|
||
k++;
|
||
}
|
||
fprintf( stderr, "\n");
|
||
close( fd);
|
||
abort();
|
||
return (0);
|
||
}
|
||
|
||
close( fd);
|
||
|
||
return (n);
|
||
} /* lcbe_get_exec_result */
|
||
|
||
/**
|
||
* Получить путь до библиотек.
|
||
*/
|
||
static const char *
|
||
lcbe_get_include_path( const char *name,
|
||
int ptr_bit_size)
|
||
{
|
||
const char *r = 0;
|
||
|
||
if ( (strcmp( name, "c") == 0) )
|
||
{
|
||
r = lcbe_info.tools.include_path;
|
||
|
||
} else if ( (strcmp( name, "c++-stl") == 0) )
|
||
{
|
||
r = lcbe_info.tools.include_cpp_stl_path;
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_get_include_path */
|
||
|
||
/**
|
||
* Получить путь до библиотек.
|
||
*/
|
||
static const char *
|
||
lcbe_get_lib_path( const char *name,
|
||
int ptr_bit_size)
|
||
{
|
||
const char *r = 0;
|
||
|
||
if ( (strcmp( name, "mvec") == 0) )
|
||
{
|
||
if ( (ptr_bit_size == 32) )
|
||
{
|
||
r = lcbe_info.tools.gcc_lib32_path;
|
||
} else
|
||
{
|
||
r = lcbe_info.tools.gcc_lib64_path;
|
||
}
|
||
} else if ( (strcmp( name, "c") == 0) )
|
||
{
|
||
if ( (ptr_bit_size == 32) )
|
||
{
|
||
r = lcbe_info.tools.lib32_path;
|
||
} else
|
||
{
|
||
r = lcbe_info.tools.lib64_path;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_get_lib_path */
|
||
|
||
/**
|
||
* Получить для программы полный путь размещения программы.
|
||
*/
|
||
static const char *
|
||
lcbe_get_toolchain_path( const char *tool,
|
||
int ptr_bit_size)
|
||
{
|
||
const char *r = 0;
|
||
|
||
if ( (strcmp( tool, "ld") == 0) )
|
||
{
|
||
r = lcbe_info.tools.ld_path;
|
||
|
||
} else if ( (strcmp( tool, "as") == 0) )
|
||
{
|
||
r = lcbe_info.tools.as_path;
|
||
|
||
} else if ( (strcmp( tool, "gcc") == 0) )
|
||
{
|
||
r = lcbe_info.tools.gcc_path;
|
||
|
||
} else if ( (strcmp( tool, "fs") == 0) )
|
||
{
|
||
r = lcbe_info.tools.fs;
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_get_toolchain_path */
|
||
|
||
/**
|
||
* Получить название программы вместе с полным путем.
|
||
*/
|
||
static const char *
|
||
lcbe_get_toolchain( const char *tool,
|
||
int ptr_bit_size)
|
||
{
|
||
const char *r = 0;
|
||
|
||
if ( (strcmp( tool, "ld") == 0) )
|
||
{
|
||
r = lcbe_info.tools.ld;
|
||
|
||
} else if ( (strcmp( tool, "as") == 0) )
|
||
{
|
||
r = lcbe_info.tools.as;
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_get_toolchain */
|
||
|
||
/**
|
||
* Получить название или местоположение утилиты.
|
||
*/
|
||
const char *
|
||
LCCRT_ASM_FUNC_GETTOOL( const char *targ, const char *type, const char *name)
|
||
{
|
||
const char *r = 0;
|
||
|
||
if ( (strcmp( targ, "e2k32") == 0)
|
||
|| (strcmp( targ, "e2k64") == 0) )
|
||
{
|
||
int ptr_bits = (strcmp( targ, "e2k32") == 0) ? 32 : 64;
|
||
|
||
if ( (strcmp( type, "tool") == 0) )
|
||
{
|
||
r = lcbe_get_toolchain( name, ptr_bits);
|
||
|
||
} else if ( (strcmp( type, "tool_path") == 0) )
|
||
{
|
||
r = lcbe_get_toolchain_path( name, ptr_bits);
|
||
|
||
} else if ( (strcmp( type, "lib_path") == 0) )
|
||
{
|
||
r = lcbe_get_lib_path( name, ptr_bits);
|
||
|
||
} else if ( (strcmp( type, "include_path") == 0) )
|
||
{
|
||
r = lcbe_get_include_path( name, ptr_bits);
|
||
}
|
||
}
|
||
|
||
r = r ? r : "";
|
||
|
||
return (r);
|
||
} /* LCCRT_ASM_FUNC_GETTOOL */
|
||
|
||
/**
|
||
* Разбор строки из конфигурационного файла в формате "name : value".
|
||
* (В строку s вставляются символы '0' и возвращаются указатели по подстроки.)
|
||
*/
|
||
static int
|
||
lcbe_parse_config_line( char *s, char **name, char **value)
|
||
{
|
||
int r = 0;
|
||
int i = 0;
|
||
|
||
i += lcbe_skip_space( s + i);
|
||
if ( (s[i] == 0)
|
||
|| (s[i] == '#') )
|
||
{
|
||
/* Встретили комментарий. */
|
||
} else
|
||
{
|
||
int n0 = 0;
|
||
int n1 = 0;
|
||
int v0 = 0;
|
||
int v1 = 0;
|
||
|
||
n0 = i;
|
||
i += lcbe_skip_str( s + i);
|
||
i = (s[i] == ':') ? (i - 1) : i;
|
||
n1 = i;
|
||
i += lcbe_skip_space( s + i);
|
||
if ( !((n0 < n1)
|
||
&& (s[i] == ':')) )
|
||
{
|
||
r = -1;
|
||
} else
|
||
{
|
||
r = 1;
|
||
i++;
|
||
i += lcbe_skip_space( s + i);
|
||
v0 = i;
|
||
while ( s[i] && (s[i] != '#') ) i++;
|
||
v1 = i;
|
||
(*name) = s + n0;
|
||
(*value) = s + v0;
|
||
s[n1] = 0;
|
||
v1--;
|
||
while ( (v1 >= v0)
|
||
&& isspace( (int)s[v1]) )
|
||
{
|
||
v1--;
|
||
}
|
||
s[v1+1] = 0;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lcbe_parse_config_line */
|
||
|
||
/**
|
||
* Чтение настроек из файла конфигурации.
|
||
*/
|
||
static void
|
||
lcbe_parse_config_file( lcbe_config_t *cnf, lcbe_tools_t *tls)
|
||
{
|
||
FILE *f = 0;
|
||
|
||
f = fopen( cnf->lcbe_conf, "r");
|
||
if ( !f )
|
||
{
|
||
fprintf( stderr, "Can't open file with lcbe-configuration [%s]\n", cnf->lcbe_conf);
|
||
abort();
|
||
} else
|
||
{
|
||
int n = 0;
|
||
char *ld = 0;
|
||
size_t ld_len = 0;
|
||
|
||
while ( !feof( f) )
|
||
{
|
||
int v = 0;
|
||
char *name = 0;
|
||
char *value = 0;
|
||
|
||
if ( (getline( &ld, &ld_len, f) > 0)
|
||
&& ((v = lcbe_parse_config_line( ld, &name, &value)) > 0) )
|
||
{
|
||
if ( lcbe_str_eq( name, "cc-config") )
|
||
{
|
||
cnf->lcbe_cc_config = lcbe_reinit_str( cnf->lcbe_cc_config, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "ld") )
|
||
{
|
||
tls->ld = lcbe_reinit_str( tls->ld, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "as") )
|
||
{
|
||
tls->as = lcbe_reinit_str( tls->as, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "fs") )
|
||
{
|
||
tls->fs = lcbe_reinit_str( tls->fs, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "include") )
|
||
{
|
||
tls->include_path = lcbe_reinit_str( tls->include_path, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "lib32") )
|
||
{
|
||
tls->lib32_path = lcbe_reinit_str( tls->lib32_path, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "lib64") )
|
||
{
|
||
tls->lib64_path = lcbe_reinit_str( tls->lib64_path, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "cc-base") )
|
||
{
|
||
tls->gcc_base_path = lcbe_reinit_str( tls->gcc_base_path, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "cc-lib32") )
|
||
{
|
||
tls->gcc_lib32_path = lcbe_reinit_str( tls->gcc_lib32_path, value);
|
||
|
||
} else if ( lcbe_str_eq( name, "cc-lib64") )
|
||
{
|
||
tls->gcc_lib64_path = lcbe_reinit_str( tls->gcc_lib64_path, value);
|
||
} else
|
||
{
|
||
fprintf( stderr, "Wrong parameter's name in file with cc-configuration [%s]\n", name);
|
||
v = -1;
|
||
}
|
||
} else if ( (v == -1) )
|
||
{
|
||
fprintf( stderr, "Wrong format in file with cc-configuration!\n");
|
||
}
|
||
|
||
if ( (v == -1) )
|
||
{
|
||
fprintf( stderr, " line number : %d\n", n);
|
||
fprintf( stderr, " line : [%s]\n", ld);
|
||
abort();
|
||
}
|
||
|
||
n++;
|
||
}
|
||
|
||
if ( ld )
|
||
{
|
||
free( ld);
|
||
}
|
||
}
|
||
|
||
fclose( f);
|
||
|
||
return;
|
||
} /* lcbe_parse_config_file */
|
||
|
||
/**
|
||
* Вычисление утилит на базе параметров конфигурации.
|
||
*/
|
||
static void
|
||
lcbe_init_library_tools( lcbe_config_t *cnf, lcbe_tools_t *tls)
|
||
{
|
||
char buf[4096];
|
||
char *ld_args[] = {"cc-config", "-print-prog-name=ld", 0};
|
||
char *as_args[] = {"cc-config", "-print-prog-name=as", 0};
|
||
char *fs_args[] = {"cc-config", "-print-config=fs-dir", 0};
|
||
char *in_args[] = {"cc-config", "-print-internal-dir=include", 0};
|
||
char *in_cpp_stl_args[] = {"cc-config", "-print-internal-dir=include-c++-stl", 0};
|
||
char *gcc_base_args[] = {"cc-config", "-print-internal-dir=base", 0};
|
||
|
||
tls->ld = lcbe_reinit_str( tls->ld, getenv( "LCBE_LD"));
|
||
tls->as = lcbe_reinit_str( tls->as, getenv( "LCBE_AS"));
|
||
tls->include_path = lcbe_reinit_str( tls->include_path, getenv( "LCBE_INCLUDE"));
|
||
tls->lib32_path = lcbe_reinit_str( tls->lib32_path, getenv( "LCBE_LIB32"));
|
||
tls->lib64_path = lcbe_reinit_str( tls->lib64_path, getenv( "LCBE_LIB64"));
|
||
tls->gcc_base_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_BASE"));
|
||
tls->gcc_lib32_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_LIB32"));
|
||
tls->gcc_lib64_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_LIB64"));
|
||
tls->fs = lcbe_reinit_str( tls->fs, getenv( "LCBE_FS"));
|
||
|
||
if ( !cnf->lcbe_cc_config )
|
||
{
|
||
if ( !tls->ld
|
||
|| !tls->as
|
||
|| !tls->fs
|
||
|| !tls->gcc_base_path )
|
||
{
|
||
fprintf( stderr, "One of variables [ld], [as], [lcc-base] or [fs] doesn't set, "
|
||
"but [lcc-config] utility is unknown!\n");
|
||
abort();
|
||
}
|
||
}
|
||
|
||
if ( 0 )
|
||
{
|
||
if ( !tls->ld )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, ld_args, 4095, buf);
|
||
tls->ld = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->as )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, as_args, 4095, buf);
|
||
tls->as = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->fs )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, fs_args, 4095, buf);
|
||
tls->fs = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->gcc_base_path )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, gcc_base_args, 4095, buf);
|
||
tls->gcc_base_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
tls->ld_path = dirname( strdup( tls->ld));
|
||
tls->as_path = dirname( strdup( tls->ld));
|
||
|
||
if ( !tls->gcc_lib32_path )
|
||
{
|
||
snprintf( buf, 4096, "ls -l %s/lib/ptr32 >& /dev/null", tls->gcc_base_path);
|
||
snprintf( buf, 4096, "%s/lib%s", tls->gcc_base_path, (system( buf) == 0) ? "/ptr32" : "32");
|
||
tls->gcc_lib32_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->gcc_lib64_path )
|
||
{
|
||
snprintf( buf, 4096, "ls -l %s/lib/ptr64 >& /dev/null", tls->gcc_base_path);
|
||
snprintf( buf, 4096, "%s/lib%s", tls->gcc_base_path, (system( buf) == 0) ? "/ptr64" : "64");
|
||
tls->gcc_lib64_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->include_path )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, in_args, 4095, buf);
|
||
tls->include_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->include_cpp_stl_path )
|
||
{
|
||
lcbe_get_exec_result( cnf->lcbe_cc_config, in_cpp_stl_args, 4095, buf);
|
||
tls->include_cpp_stl_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->lib32_path )
|
||
{
|
||
snprintf( buf, 4096, "%s/usr/lib32", tls->fs);
|
||
tls->lib32_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
|
||
if ( !tls->lib64_path )
|
||
{
|
||
snprintf( buf, 4096, "%s/usr/lib64", tls->fs);
|
||
tls->lib64_path = lcbe_reinit_str( 0, buf);
|
||
}
|
||
}
|
||
|
||
return;
|
||
} /* lcbe_init_library_tools */
|
||
|
||
/**
|
||
* Вычисление базовых параметров конфигурации библиотеки.
|
||
*/
|
||
static void
|
||
lcbe_init_config( lcbe_config_t *cnf, lcbe_tools_t *tls)
|
||
{
|
||
Dl_info dli;
|
||
char *s = 0;
|
||
char *t = 0;
|
||
|
||
memset( cnf, 0, sizeof( cnf[0]));
|
||
memset( tls, 0, sizeof( tls[0]));
|
||
|
||
cnf->verbose = lcbe_is_option( "LCBE_VERBOSE", 0) ? ~0 : 0;
|
||
|
||
dladdr( (void *)&lcbe_init_config, &dli);
|
||
s = strdup( dli.dli_fname);
|
||
cnf->lcbe_conf = lcbe_concat_str_by( strdup( basename( s)), ".conf");
|
||
free( s);
|
||
|
||
s = getenv( "LCBE_HOME");
|
||
if ( s )
|
||
{
|
||
s = strdup( s);
|
||
} else
|
||
{
|
||
t = realpath( dli.dli_fname, 0);
|
||
if ( !t )
|
||
{
|
||
fprintf( stderr, "Can't resolve real path of lcbe-library's location [%s]\n", dli.dli_fname);
|
||
abort();
|
||
}
|
||
|
||
s = dirname( t);
|
||
if ( !s )
|
||
{
|
||
fprintf( stderr, "Can't resolve directory of lcbe-library's location [%s]\n", t);
|
||
abort();
|
||
}
|
||
|
||
s = strdup( s);
|
||
free( t);
|
||
}
|
||
|
||
t = cnf->lcbe_conf;
|
||
cnf->lcbe_home = s;
|
||
cnf->lcbe_conf = lcbe_concat_str_by( lcbe_concat_str_by( strdup( s), "/"), t);
|
||
free( t);
|
||
cnf->lcbe_conf = lcbe_reinit_str( cnf->lcbe_conf, getenv( "LCBE_CONF"));
|
||
|
||
if ( cnf->verbose )
|
||
{
|
||
fprintf( stderr, "\nLCBE (LCCRT-plugin) library config:\n\n");
|
||
fprintf( stderr, " LCBE_VERBOSE : %s\n", getenv( "LCBE_VERBOSE"));
|
||
fprintf( stderr, " LCBE_HOME : %s\n", cnf->lcbe_home);
|
||
fprintf( stderr, " LCBE_CONF : %s\n", cnf->lcbe_conf);
|
||
}
|
||
|
||
lcbe_parse_config_file( cnf, tls);
|
||
cnf->lcbe_cc_config = lcbe_reinit_str( cnf->lcbe_cc_config, getenv( "LCBE_CC_CONFIG"));
|
||
|
||
if ( cnf->verbose )
|
||
{
|
||
fprintf( stderr, " LCBE_CC_CONFIG : %s\n", cnf->lcbe_cc_config);
|
||
}
|
||
|
||
lcbe_init_library_tools( cnf, tls);
|
||
|
||
if ( cnf->verbose )
|
||
{
|
||
fprintf( stderr, " LCBE_LD : %s\n", tls->ld);
|
||
fprintf( stderr, " LCBE_AS : %s\n", tls->as);
|
||
fprintf( stderr, " LCBE_FS : %s\n", tls->fs);
|
||
fprintf( stderr, " LCBE_INCLUDE : %s\n", tls->include_path);
|
||
fprintf( stderr, " LCBE_INCLUDE_CPP_STL : %s\n", tls->include_cpp_stl_path);
|
||
fprintf( stderr, " LCBE_LIB32 : %s\n", tls->lib32_path);
|
||
fprintf( stderr, " LCBE_LIB64 : %s\n", tls->lib64_path);
|
||
fprintf( stderr, " LCBE_CC_BASE : %s\n", tls->gcc_base_path);
|
||
fprintf( stderr, " LCBE_CC_LIB32 : %s\n", tls->gcc_lib32_path);
|
||
fprintf( stderr, " LCBE_CC_LIB64 : %s\n", tls->gcc_lib64_path);
|
||
}
|
||
|
||
return;
|
||
} /* lcbe_init_config */
|
||
|
||
/**
|
||
* Инициализация библиотеки.
|
||
*/
|
||
static void
|
||
lcbe_init( void)
|
||
{
|
||
lcbe_tools_t *t = &(lcbe_info.tools);
|
||
lcbe_config_t *c = &(lcbe_info.conf);
|
||
|
||
lcbe_init_config( c, t);
|
||
|
||
c->cc_flags = lcbe_get_option( "LCBE_CFLAGS", 0);
|
||
c->save_temps = lcbe_get_option( "LCBE_SAVE", 0);
|
||
|
||
if ( c->verbose )
|
||
{
|
||
fprintf( stderr, " LCBE_CFLAGS : %s\n", c->cc_flags);
|
||
fprintf( stderr, " LCBE_SAVE : %s\n", c->save_temps);
|
||
fprintf( stderr, "\n");
|
||
}
|
||
|
||
return;
|
||
} /* lcbe_init */
|
||
|
||
/**
|
||
* Завершение работы библиотеки.
|
||
*/
|
||
static void
|
||
lcbe_done( void)
|
||
{
|
||
return;
|
||
} /* lcbe_done */
|
||
|