|
|
9ca8c4 |
/*******************************************************************/
|
|
|
eac61a |
/* slibtool: a strong libtool implementation, written in C */
|
|
|
49181b |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
9ca8c4 |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
9ca8c4 |
/*******************************************************************/
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
#include <stdint.h>
|
|
|
0cbb20 |
#include <string.h>
|
|
|
9ca8c4 |
#include <unistd.h>
|
|
|
d5e3ae |
#include <stdlib.h>
|
|
|
d5e3ae |
#include <stdbool.h>
|
|
|
9ca8c4 |
#include <fcntl.h>
|
|
|
d5e3ae |
#include <spawn.h>
|
|
|
6ab3f1 |
#include <sys/mman.h>
|
|
|
d5e3ae |
#include <sys/wait.h>
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
#define ARGV_DRIVER
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
#include <slibtool/slibtool.h>
|
|
|
9f24d2 |
#include "slibtool_version.h"
|
|
|
9ca8c4 |
#include "slibtool_driver_impl.h"
|
|
|
a126a7 |
#include "slibtool_objlist_impl.h"
|
|
|
8069c3 |
#include "slibtool_errinfo_impl.h"
|
|
|
499a71 |
#include "slibtool_lconf_impl.h"
|
|
|
11f3c7 |
#include "slibtool_ar_impl.h"
|
|
|
9ca8c4 |
#include "argv/argv.h"
|
|
|
9ca8c4 |
|
|
|
d5e3ae |
extern char ** environ;
|
|
|
d5e3ae |
|
|
|
8f60d4 |
/* annotation strings */
|
|
|
8f60d4 |
static const char cfgexplicit[] = "command-line argument";
|
|
|
8f60d4 |
static const char cfglconf[] = "derived from <libtool>";
|
|
|
8f60d4 |
|
|
|
9f24d2 |
/* package info */
|
|
|
9f24d2 |
static const struct slbt_source_version slbt_src_version = {
|
|
|
9f24d2 |
SLBT_TAG_VER_MAJOR,
|
|
|
9f24d2 |
SLBT_TAG_VER_MINOR,
|
|
|
9f24d2 |
SLBT_TAG_VER_PATCH,
|
|
|
9f24d2 |
SLIBTOOL_GIT_VERSION
|
|
|
9f24d2 |
};
|
|
|
5a9161 |
|
|
|
358030 |
/* default fd context */
|
|
|
358030 |
static const struct slbt_fd_ctx slbt_default_fdctx = {
|
|
|
358030 |
.fdin = STDIN_FILENO,
|
|
|
358030 |
.fdout = STDOUT_FILENO,
|
|
|
358030 |
.fderr = STDERR_FILENO,
|
|
|
358030 |
.fdcwd = AT_FDCWD,
|
|
|
358030 |
.fddst = AT_FDCWD,
|
|
|
358030 |
.fdlog = (-1),
|
|
|
358030 |
};
|
|
|
358030 |
|
|
|
1cd1cf |
static const char aclr_reset [] = "\x1b[0m";
|
|
|
1cd1cf |
static const char aclr_bold [] = "\x1b[1m";
|
|
|
1cd1cf |
static const char aclr_red [] = "\x1b[31m";
|
|
|
1cd1cf |
static const char aclr_green [] = "\x1b[32m";
|
|
|
1cd1cf |
static const char aclr_yellow [] = "\x1b[33m";
|
|
|
1cd1cf |
static const char aclr_blue [] = "\x1b[34m";
|
|
|
1cd1cf |
static const char aclr_magenta [] = "\x1b[35m";
|
|
|
1cd1cf |
static const char aclr_cyan [] = "\x1b[36m";
|
|
|
1cd1cf |
static const char aclr_white [] = "\x1b[37m";
|
|
|
caf7d0 |
|
|
|
9ca8c4 |
|
|
|
d4c3e3 |
static void slbt_output_raw_vector(int fderr, char ** argv, char ** envp, bool fcolor)
|
|
|
caf7d0 |
{
|
|
|
caf7d0 |
char ** parg;
|
|
|
caf7d0 |
char * dot;
|
|
|
caf7d0 |
const char * color;
|
|
|
1cd1cf |
const char * prev;
|
|
|
1cd1cf |
const char * prog;
|
|
|
caf7d0 |
|
|
|
d3ca02 |
(void)envp;
|
|
|
d3ca02 |
|
|
|
d4c3e3 |
if (fcolor)
|
|
|
a82cc2 |
slbt_dprintf(fderr,"%s%s",aclr_bold,aclr_red);
|
|
|
caf7d0 |
|
|
|
a82cc2 |
slbt_dprintf(fderr,"\n\n\n%s",argv[0]);
|
|
|
caf7d0 |
|
|
|
1cd1cf |
for (prev=0,prog=0,parg=&argv[1]; *parg; parg++) {
|
|
|
1cd1cf |
dot = strrchr(*parg,'.');
|
|
|
1cd1cf |
|
|
|
1cd1cf |
if (!fcolor) {
|
|
|
caf7d0 |
color = "";
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!prog && (parg[0][0] != '-')) {
|
|
|
1cd1cf |
color = aclr_magenta;
|
|
|
1cd1cf |
prog = *parg;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strcmp(parg[0],"-o")) {
|
|
|
1cd1cf |
color = aclr_white;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strcmp(parg[0],"-c")) {
|
|
|
caf7d0 |
color = aclr_green;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strncmp(parg[0],"-Wl,",4)) {
|
|
|
1cd1cf |
color = aclr_magenta;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (prev == aclr_white) {
|
|
|
1cd1cf |
color = prev;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (dot && !strcmp(dot,".o")) {
|
|
|
caf7d0 |
color = aclr_cyan;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (dot && !strcmp(dot,".lo")) {
|
|
|
1cd1cf |
color = aclr_cyan;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (dot && !strcmp(dot,".la")) {
|
|
|
caf7d0 |
color = aclr_yellow;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strcmp(parg[0],"-dlopen")) {
|
|
|
1cd1cf |
color = aclr_yellow;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strcmp(parg[0],"-dlpreopen")) {
|
|
|
1cd1cf |
color = aclr_yellow;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (!strcmp(parg[0],"-objectlist")) {
|
|
|
1cd1cf |
color = aclr_yellow;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (*parg[0] == '-') {
|
|
|
1cd1cf |
color = aclr_blue;
|
|
|
1cd1cf |
prev = color;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else if (prev) {
|
|
|
1cd1cf |
color = prev;
|
|
|
1cd1cf |
prev = 0;
|
|
|
1cd1cf |
|
|
|
1cd1cf |
} else {
|
|
|
1cd1cf |
color = aclr_yellow;
|
|
|
1cd1cf |
}
|
|
|
caf7d0 |
|
|
|
a82cc2 |
slbt_dprintf(fderr," %s%s",color,*parg);
|
|
|
caf7d0 |
}
|
|
|
caf7d0 |
|
|
|
a82cc2 |
slbt_dprintf(fderr,"%s\n\n",fcolor ? aclr_reset : "");
|
|
|
caf7d0 |
}
|
|
|
caf7d0 |
|
|
|
4b56de |
slbt_hidden const char * slbt_program_name(const char * path)
|
|
|
99c275 |
{
|
|
|
99c275 |
return argv_program_name(path);
|
|
|
99c275 |
}
|
|
|
99c275 |
|
|
|
c3d88b |
|
|
|
4b56de |
slbt_hidden int slbt_optv_init(
|
|
|
c3d88b |
const struct argv_option options[],
|
|
|
c3d88b |
const struct argv_option ** optv)
|
|
|
c3d88b |
{
|
|
|
c3d88b |
return argv_optv_init(options,optv);
|
|
|
c3d88b |
}
|
|
|
c3d88b |
|
|
|
c3d88b |
|
|
|
4b56de |
slbt_hidden void slbt_argv_scan(
|
|
|
c3d88b |
char ** argv,
|
|
|
c3d88b |
const struct argv_option ** optv,
|
|
|
c3d88b |
struct argv_ctx * ctx,
|
|
|
c3d88b |
struct argv_meta * meta)
|
|
|
c3d88b |
{
|
|
|
bc3103 |
argv_scan(argv,optv,ctx,meta);
|
|
|
c3d88b |
}
|
|
|
c3d88b |
|
|
|
c3d88b |
|
|
|
4b56de |
slbt_hidden struct argv_meta * slbt_argv_get(
|
|
|
c3d88b |
char ** argv,
|
|
|
c3d88b |
const struct argv_option ** optv,
|
|
|
c3d88b |
int flags,
|
|
|
c3d88b |
int fd)
|
|
|
c3d88b |
{
|
|
|
c3d88b |
return argv_get(argv,optv,flags,fd);
|
|
|
c3d88b |
}
|
|
|
c3d88b |
|
|
|
c3d88b |
|
|
|
4b56de |
slbt_hidden void slbt_argv_free(struct argv_meta * meta)
|
|
|
c3d88b |
{
|
|
|
bc3103 |
argv_free(meta);
|
|
|
c3d88b |
}
|
|
|
c3d88b |
|
|
|
c3d88b |
|
|
|
4b56de |
slbt_hidden void slbt_argv_usage(
|
|
|
6b2413 |
int fd,
|
|
|
6b2413 |
const char * header,
|
|
|
6b2413 |
const struct argv_option ** optv,
|
|
|
6b2413 |
const char * mode)
|
|
|
6b2413 |
{
|
|
|
bc3103 |
argv_usage(fd,header,optv,mode);
|
|
|
6b2413 |
}
|
|
|
6b2413 |
|
|
|
6b2413 |
|
|
|
4b56de |
slbt_hidden void slbt_argv_usage_plain(
|
|
|
6b2413 |
int fd,
|
|
|
6b2413 |
const char * header,
|
|
|
6b2413 |
const struct argv_option ** optv,
|
|
|
6b2413 |
const char * mode)
|
|
|
6b2413 |
{
|
|
|
bc3103 |
argv_usage_plain(fd,header,optv,mode);
|
|
|
6b2413 |
}
|
|
|
6b2413 |
|
|
|
6b2413 |
|
|
|
4b56de |
slbt_hidden uint64_t slbt_argv_flags(uint64_t flags)
|
|
|
9ca8c4 |
{
|
|
|
9ca8c4 |
uint32_t ret = 0;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
if (flags & SLBT_DRIVER_VERBOSITY_NONE)
|
|
|
9ca8c4 |
ret |= ARGV_VERBOSITY_NONE;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
if (flags & SLBT_DRIVER_VERBOSITY_ERRORS)
|
|
|
9ca8c4 |
ret |= ARGV_VERBOSITY_ERRORS;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
if (flags & SLBT_DRIVER_VERBOSITY_STATUS)
|
|
|
9ca8c4 |
ret |= ARGV_VERBOSITY_STATUS;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
return ret;
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
a126a7 |
static int slbt_free_argv_buffer(
|
|
|
a126a7 |
struct slbt_split_vector * sargv,
|
|
|
a126a7 |
struct slbt_obj_list * objlistv)
|
|
|
0cbb20 |
{
|
|
|
a126a7 |
struct slbt_obj_list * objlistp;
|
|
|
a126a7 |
|
|
|
0cbb20 |
if (sargv->dargs)
|
|
|
0cbb20 |
free(sargv->dargs);
|
|
|
0cbb20 |
|
|
|
0cbb20 |
if (sargv->dargv)
|
|
|
0cbb20 |
free(sargv->dargv);
|
|
|
0cbb20 |
|
|
|
0cbb20 |
if (sargv->targv)
|
|
|
0cbb20 |
free(sargv->targv);
|
|
|
0cbb20 |
|
|
|
a126a7 |
if (objlistv) {
|
|
|
a126a7 |
for (objlistp=objlistv; objlistp->name; objlistp++) {
|
|
|
a126a7 |
free(objlistp->objv);
|
|
|
a126a7 |
free(objlistp->addr);
|
|
|
a126a7 |
}
|
|
|
a126a7 |
|
|
|
a126a7 |
free(objlistv);
|
|
|
a126a7 |
}
|
|
|
a126a7 |
|
|
|
0cbb20 |
return -1;
|
|
|
0cbb20 |
}
|
|
|
0cbb20 |
|
|
|
4b56de |
slbt_hidden int slbt_driver_usage(
|
|
|
a82cc2 |
int fdout,
|
|
|
9ca8c4 |
const char * program,
|
|
|
9ca8c4 |
const char * arg,
|
|
|
d58d2f |
const struct argv_option ** optv,
|
|
|
0cbb20 |
struct argv_meta * meta,
|
|
|
d4c3e3 |
struct slbt_split_vector * sargv,
|
|
|
a126a7 |
struct slbt_obj_list * objlistv,
|
|
|
d4c3e3 |
int noclr)
|
|
|
9ca8c4 |
{
|
|
|
9ca8c4 |
char header[512];
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
snprintf(header,sizeof(header),
|
|
|
9ca8c4 |
"Usage: %s [options] <file>...\n" "Options:\n",
|
|
|
9ca8c4 |
program);
|
|
|
9ca8c4 |
|
|
|
d4c3e3 |
switch (noclr) {
|
|
|
d4c3e3 |
case 0:
|
|
|
d4c3e3 |
argv_usage(fdout,header,optv,arg);
|
|
|
d4c3e3 |
break;
|
|
|
d4c3e3 |
|
|
|
d4c3e3 |
default:
|
|
|
d4c3e3 |
argv_usage_plain(fdout,header,optv,arg);
|
|
|
d4c3e3 |
break;
|
|
|
d4c3e3 |
}
|
|
|
d4c3e3 |
|
|
|
9ca8c4 |
argv_free(meta);
|
|
|
a126a7 |
slbt_free_argv_buffer(sargv,objlistv);
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
return SLBT_USAGE;
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
static struct slbt_driver_ctx_impl * slbt_driver_ctx_alloc(
|
|
|
a82cc2 |
const struct slbt_fd_ctx * fdctx,
|
|
|
0cbb20 |
const struct slbt_common_ctx * cctx,
|
|
|
684b80 |
struct slbt_split_vector * sargv,
|
|
|
a126a7 |
struct slbt_obj_list * objlistv,
|
|
|
9da202 |
char ** envp,
|
|
|
9da202 |
size_t ndlopen)
|
|
|
9ca8c4 |
{
|
|
|
9ca8c4 |
struct slbt_driver_ctx_alloc * ictx;
|
|
|
9ca8c4 |
size_t size;
|
|
|
41c05b |
int elements;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
size = sizeof(struct slbt_driver_ctx_alloc);
|
|
|
9ca8c4 |
|
|
|
0cbb20 |
if (!(ictx = calloc(1,size))) {
|
|
|
a126a7 |
slbt_free_argv_buffer(sargv,objlistv);
|
|
|
9ca8c4 |
return 0;
|
|
|
0cbb20 |
}
|
|
|
0cbb20 |
|
|
|
9da202 |
if (ndlopen) {
|
|
|
a07095 |
if (!(ictx->ctx.dlopenv = calloc(ndlopen+1,sizeof(*ictx->ctx.dlopenv)))) {
|
|
|
9da202 |
free(ictx);
|
|
|
9da202 |
slbt_free_argv_buffer(sargv,objlistv);
|
|
|
9da202 |
return 0;
|
|
|
9da202 |
}
|
|
|
9da202 |
|
|
|
9da202 |
ictx->ctx.ndlopen = ndlopen;
|
|
|
9da202 |
}
|
|
|
9da202 |
|
|
|
0cbb20 |
ictx->ctx.dargs = sargv->dargs;
|
|
|
0cbb20 |
ictx->ctx.dargv = sargv->dargv;
|
|
|
0cbb20 |
ictx->ctx.targv = sargv->targv;
|
|
|
0cbb20 |
ictx->ctx.cargv = sargv->cargv;
|
|
|
684b80 |
ictx->ctx.envp = envp;
|
|
|
9ca8c4 |
|
|
|
a82cc2 |
memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx));
|
|
|
a82cc2 |
memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
|
|
|
9ca8c4 |
|
|
|
41c05b |
elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
|
|
|
41c05b |
|
|
|
41c05b |
ictx->ctx.errinfp = &ictx->ctx.erriptr[0];
|
|
|
41c05b |
ictx->ctx.erricap = &ictx->ctx.erriptr[--elements];
|
|
|
41c05b |
|
|
|
a126a7 |
ictx->ctx.objlistv = objlistv;
|
|
|
a126a7 |
|
|
|
53c651 |
ictx->ctx.ctx.errv = ictx->ctx.errinfp;
|
|
|
a126a7 |
|
|
|
9ca8c4 |
return &ictx->ctx;
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
ea4137 |
static int slbt_lib_get_driver_ctx_fail(
|
|
|
38b351 |
struct slbt_driver_ctx * dctx,
|
|
|
38b351 |
struct argv_meta * meta)
|
|
|
9ca8c4 |
{
|
|
|
38b351 |
if (dctx) {
|
|
|
38b351 |
slbt_output_error_vector(dctx);
|
|
|
ea4137 |
slbt_lib_free_driver_ctx(dctx);
|
|
|
38b351 |
} else {
|
|
|
38b351 |
argv_free(meta);
|
|
|
38b351 |
}
|
|
|
38b351 |
|
|
|
9ca8c4 |
return -1;
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
af7db9 |
|
|
|
b54f55 |
static int slbt_driver_fail_incompatible_args(
|
|
|
89f5ab |
int fderr,
|
|
|
89f5ab |
uint64_t drvflags,
|
|
|
89f5ab |
struct argv_meta * meta,
|
|
|
89f5ab |
const char * program,
|
|
|
89f5ab |
const char * afirst,
|
|
|
89f5ab |
const char * asecond)
|
|
|
89f5ab |
{
|
|
|
89f5ab |
int fcolor;
|
|
|
89f5ab |
|
|
|
d4c3e3 |
fcolor = (drvflags & SLBT_DRIVER_ANNOTATE_NEVER)
|
|
|
d4c3e3 |
? 0 : isatty(fderr);
|
|
|
d4c3e3 |
|
|
|
89f5ab |
if (drvflags & SLBT_DRIVER_VERBOSITY_ERRORS){
|
|
|
d4c3e3 |
if (fcolor)
|
|
|
89f5ab |
slbt_dprintf(
|
|
|
89f5ab |
fderr,"%s%s",
|
|
|
89f5ab |
aclr_bold,aclr_red);
|
|
|
89f5ab |
|
|
|
89f5ab |
slbt_dprintf(fderr,
|
|
|
89f5ab |
"%s: error: incompatible arguments: "
|
|
|
89f5ab |
"at the most one of %s and %s "
|
|
|
89f5ab |
"may be used.\n",
|
|
|
89f5ab |
program,afirst,asecond);
|
|
|
89f5ab |
|
|
|
89f5ab |
if (fcolor)
|
|
|
89f5ab |
slbt_dprintf(
|
|
|
89f5ab |
fderr,"%s",
|
|
|
89f5ab |
aclr_reset);
|
|
|
89f5ab |
}
|
|
|
89f5ab |
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(0,meta);
|
|
|
89f5ab |
}
|
|
|
89f5ab |
|
|
|
261127 |
|
|
|
261127 |
static int slbt_driver_parse_tool_argv(const char * tool, char *** tool_argv)
|
|
|
261127 |
{
|
|
|
261127 |
int argc;
|
|
|
261127 |
char ** argv;
|
|
|
261127 |
const char * ch;
|
|
|
261127 |
const char * mark;
|
|
|
261127 |
|
|
|
261127 |
if (!(ch = tool))
|
|
|
261127 |
return 0;
|
|
|
261127 |
|
|
|
261127 |
argc = 1;
|
|
|
261127 |
|
|
|
261127 |
for (; *ch == ' '; )
|
|
|
261127 |
ch++;
|
|
|
261127 |
|
|
|
261127 |
for (; *ch; ) {
|
|
|
261127 |
if (*ch++ == ' ') {
|
|
|
261127 |
argc++;
|
|
|
261127 |
|
|
|
261127 |
for (; (*ch == ' '); )
|
|
|
261127 |
ch++;
|
|
|
261127 |
}
|
|
|
261127 |
}
|
|
|
261127 |
|
|
|
261127 |
if (argc == 1)
|
|
|
261127 |
return 0;
|
|
|
261127 |
|
|
|
261127 |
if (!(*tool_argv = calloc(++argc,sizeof(char *))))
|
|
|
261127 |
return -1;
|
|
|
261127 |
|
|
|
261127 |
for (ch=tool; (*ch == ' '); ch++)
|
|
|
261127 |
(void)0;
|
|
|
261127 |
|
|
|
261127 |
argv = *tool_argv;
|
|
|
261127 |
mark = ch;
|
|
|
261127 |
|
|
|
261127 |
for (; *ch; ) {
|
|
|
261127 |
if (*ch == ' ') {
|
|
|
261127 |
if (!(*argv++ = strndup(mark,ch-mark)))
|
|
|
261127 |
return -1;
|
|
|
261127 |
|
|
|
261127 |
for (; (*ch == ' '); )
|
|
|
261127 |
ch++;
|
|
|
261127 |
|
|
|
261127 |
mark = ch;
|
|
|
261127 |
} else {
|
|
|
261127 |
ch++;
|
|
|
261127 |
}
|
|
|
261127 |
}
|
|
|
261127 |
|
|
|
261127 |
if (!(*argv++ = strndup(mark,ch-mark)))
|
|
|
261127 |
return -1;
|
|
|
261127 |
|
|
|
261127 |
return 0;
|
|
|
261127 |
}
|
|
|
261127 |
|
|
|
261127 |
|
|
|
ea4137 |
int slbt_lib_get_driver_ctx(
|
|
|
9ca8c4 |
char ** argv,
|
|
|
9ca8c4 |
char ** envp,
|
|
|
1c4305 |
uint64_t flags,
|
|
|
a82cc2 |
const struct slbt_fd_ctx * fdctx,
|
|
|
9ca8c4 |
struct slbt_driver_ctx ** pctx)
|
|
|
9ca8c4 |
{
|
|
|
56cab3 |
struct slbt_split_vector sargv;
|
|
|
a126a7 |
struct slbt_obj_list * objlistv;
|
|
|
9ca8c4 |
struct slbt_driver_ctx_impl * ctx;
|
|
|
9ca8c4 |
struct slbt_common_ctx cctx;
|
|
|
d58d2f |
const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
|
|
|
9ca8c4 |
struct argv_meta * meta;
|
|
|
9ca8c4 |
struct argv_entry * entry;
|
|
|
89f5ab |
struct argv_entry * cmdstatic;
|
|
|
89f5ab |
struct argv_entry * cmdshared;
|
|
|
89f5ab |
struct argv_entry * cmdnostatic;
|
|
|
89f5ab |
struct argv_entry * cmdnoshared;
|
|
|
9ca8c4 |
const char * program;
|
|
|
499a71 |
const char * lconf;
|
|
|
499a71 |
uint64_t lflags;
|
|
|
9da202 |
size_t ndlopen;
|
|
|
a07095 |
struct argv_entry ** dlopenv;
|
|
|
771899 |
const char * cfgmeta_host;
|
|
|
d29f9c |
const char * cfgmeta_ar;
|
|
|
b4058c |
const char * cfgmeta_as;
|
|
|
b5e104 |
const char * cfgmeta_nm;
|
|
|
d29f9c |
const char * cfgmeta_ranlib;
|
|
|
fc8ee9 |
const char * cfgmeta_dlltool;
|
|
|
9ca8c4 |
|
|
|
11f3c7 |
if (flags & SLBT_DRIVER_MODE_AR)
|
|
|
11f3c7 |
argv_optv_init(slbt_ar_options,optv);
|
|
|
11f3c7 |
else
|
|
|
11f3c7 |
argv_optv_init(slbt_default_options,optv);
|
|
|
9ca8c4 |
|
|
|
358030 |
if (!fdctx)
|
|
|
358030 |
fdctx = &slbt_default_fdctx;
|
|
|
a82cc2 |
|
|
|
0cbb20 |
sargv.dargs = 0;
|
|
|
0cbb20 |
sargv.dargv = 0;
|
|
|
0cbb20 |
sargv.targv = 0;
|
|
|
0cbb20 |
sargv.cargv = 0;
|
|
|
a126a7 |
objlistv = 0;
|
|
|
9da202 |
ndlopen = 0;
|
|
|
0cbb20 |
|
|
|
626342 |
switch (slbt_split_argv(argv,flags,&sargv,&objlistv,fdctx->fderr,fdctx->fdcwd)) {
|
|
|
626342 |
case SLBT_OK:
|
|
|
626342 |
break;
|
|
|
626342 |
|
|
|
626342 |
case SLBT_USAGE:
|
|
|
626342 |
return SLBT_USAGE;
|
|
|
626342 |
|
|
|
626342 |
default:
|
|
|
626342 |
return slbt_free_argv_buffer(&sargv,objlistv);
|
|
|
626342 |
}
|
|
|
56cab3 |
|
|
|
93f9e4 |
if (!(meta = argv_get(
|
|
|
93f9e4 |
sargv.targv,optv,
|
|
|
0cbb20 |
slbt_argv_flags(flags),
|
|
|
a82cc2 |
fdctx->fderr)))
|
|
|
a126a7 |
return slbt_free_argv_buffer(&sargv,objlistv);
|
|
|
9ca8c4 |
|
|
|
499a71 |
lconf = 0;
|
|
|
9ca8c4 |
program = argv_program_name(argv[0]);
|
|
|
499a71 |
|
|
|
9ca8c4 |
memset(&cctx,0,sizeof(cctx));
|
|
|
9ca8c4 |
|
|
|
11f3c7 |
if (flags & SLBT_DRIVER_MODE_AR)
|
|
|
11f3c7 |
cctx.mode = SLBT_MODE_AR;
|
|
|
11f3c7 |
|
|
|
4c3fb7 |
else if (flags & SLBT_DRIVER_MODE_STOOLIE)
|
|
|
4c3fb7 |
cctx.mode = SLBT_MODE_STOOLIE;
|
|
|
4c3fb7 |
|
|
|
c5ee86 |
/* default flags (set at compile time and derived from symlink) */
|
|
|
c5ee86 |
cctx.drvflags = flags;
|
|
|
341c87 |
|
|
|
2bc175 |
/* full annotation when annotation is on; */
|
|
|
d4c3e3 |
if (!(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER))
|
|
|
d4c3e3 |
cctx.drvflags |= SLBT_DRIVER_ANNOTATE_FULL;
|
|
|
2bc175 |
|
|
|
89f5ab |
/* track incompatible command-line arguments */
|
|
|
89f5ab |
cmdstatic = 0;
|
|
|
89f5ab |
cmdshared = 0;
|
|
|
89f5ab |
cmdnostatic = 0;
|
|
|
89f5ab |
cmdnoshared = 0;
|
|
|
89f5ab |
|
|
|
771899 |
cfgmeta_host = 0;
|
|
|
d29f9c |
cfgmeta_ar = 0;
|
|
|
b4058c |
cfgmeta_as = 0;
|
|
|
b5e104 |
cfgmeta_nm = 0;
|
|
|
d29f9c |
cfgmeta_ranlib = 0;
|
|
|
fc8ee9 |
cfgmeta_dlltool = 0;
|
|
|
d29f9c |
|
|
|
1379f7 |
/* get options */
|
|
|
9ca8c4 |
for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
|
|
|
9ca8c4 |
if (entry->fopt) {
|
|
|
9ca8c4 |
switch (entry->tag) {
|
|
|
9ca8c4 |
case TAG_HELP:
|
|
|
949677 |
case TAG_HELP_ALL:
|
|
|
5b1d0e |
switch (cctx.mode) {
|
|
|
5b1d0e |
case SLBT_MODE_INSTALL:
|
|
|
5b1d0e |
case SLBT_MODE_UNINSTALL:
|
|
|
11f3c7 |
case SLBT_MODE_AR:
|
|
|
4c3fb7 |
case SLBT_MODE_STOOLIE:
|
|
|
5b1d0e |
break;
|
|
|
5b1d0e |
|
|
|
5b1d0e |
default:
|
|
|
5b1d0e |
return (flags & SLBT_DRIVER_VERBOSITY_USAGE)
|
|
|
5b1d0e |
? slbt_driver_usage(
|
|
|
5b1d0e |
fdctx->fdout,program,
|
|
|
5b1d0e |
entry->arg,optv,
|
|
|
a126a7 |
meta,&sargv,objlistv,
|
|
|
5b1d0e |
(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER))
|
|
|
5b1d0e |
: SLBT_USAGE;
|
|
|
5b1d0e |
}
|
|
|
5b1d0e |
|
|
|
5b1d0e |
break;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
case TAG_VERSION:
|
|
|
9ca8c4 |
cctx.drvflags |= SLBT_DRIVER_VERSION;
|
|
|
9ca8c4 |
break;
|
|
|
667ce2 |
|
|
|
499a71 |
case TAG_HEURISTICS:
|
|
|
499a71 |
cctx.drvflags |= SLBT_DRIVER_HEURISTICS;
|
|
|
499a71 |
lconf = entry->arg;
|
|
|
499a71 |
break;
|
|
|
499a71 |
|
|
|
667ce2 |
case TAG_MODE:
|
|
|
667ce2 |
if (!strcmp("clean",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_CLEAN;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("compile",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_COMPILE;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("execute",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_EXECUTE;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("finish",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_FINISH;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("install",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_INSTALL;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("link",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_LINK;
|
|
|
667ce2 |
|
|
|
667ce2 |
else if (!strcmp("uninstall",entry->arg))
|
|
|
667ce2 |
cctx.mode = SLBT_MODE_UNINSTALL;
|
|
|
11f3c7 |
|
|
|
11f3c7 |
else if (!strcmp("ar",entry->arg))
|
|
|
11f3c7 |
cctx.mode = SLBT_MODE_AR;
|
|
|
4c3fb7 |
|
|
|
4c3fb7 |
else if (!strcmp("stoolie",entry->arg))
|
|
|
4c3fb7 |
cctx.mode = SLBT_MODE_STOOLIE;
|
|
|
4c3fb7 |
|
|
|
4c3fb7 |
else if (!strcmp("slibtoolize",entry->arg))
|
|
|
4c3fb7 |
cctx.mode = SLBT_MODE_STOOLIE;
|
|
|
667ce2 |
break;
|
|
|
071d14 |
|
|
|
b9575f |
case TAG_FINISH:
|
|
|
b9575f |
cctx.mode = SLBT_MODE_FINISH;
|
|
|
b9575f |
break;
|
|
|
b9575f |
|
|
|
071d14 |
case TAG_DRY_RUN:
|
|
|
071d14 |
cctx.drvflags |= SLBT_DRIVER_DRY_RUN;
|
|
|
071d14 |
break;
|
|
|
53f4ec |
|
|
|
53f4ec |
case TAG_TAG:
|
|
|
53f4ec |
if (!strcmp("CC",entry->arg))
|
|
|
53f4ec |
cctx.tag = SLBT_TAG_CC;
|
|
|
53f4ec |
|
|
|
53f4ec |
else if (!strcmp("CXX",entry->arg))
|
|
|
53f4ec |
cctx.tag = SLBT_TAG_CXX;
|
|
|
62b4bb |
|
|
|
6e6b0f |
else if (!strcmp("FC",entry->arg))
|
|
|
6e6b0f |
cctx.tag = SLBT_TAG_FC;
|
|
|
6e6b0f |
|
|
|
1bd7a3 |
else if (!strcmp("F77",entry->arg))
|
|
|
1bd7a3 |
cctx.tag = SLBT_TAG_F77;
|
|
|
1bd7a3 |
|
|
|
fb5e7f |
else if (!strcmp("ASM",entry->arg))
|
|
|
fb5e7f |
cctx.tag = SLBT_TAG_ASM;
|
|
|
fb5e7f |
|
|
|
62b4bb |
else if (!strcmp("NASM",entry->arg))
|
|
|
62b4bb |
cctx.tag = SLBT_TAG_NASM;
|
|
|
0e609b |
|
|
|
4127b5 |
else if (!strcmp("RC",entry->arg))
|
|
|
4127b5 |
cctx.tag = SLBT_TAG_RC;
|
|
|
4127b5 |
|
|
|
0e609b |
else if (!strcmp("disable-static",entry->arg))
|
|
|
89f5ab |
cmdnostatic = entry;
|
|
|
f5fa4c |
|
|
|
f5fa4c |
else if (!strcmp("disable-shared",entry->arg))
|
|
|
89f5ab |
cmdnoshared = entry;
|
|
|
53f4ec |
break;
|
|
|
173b54 |
|
|
|
c57816 |
case TAG_INFO:
|
|
|
c57816 |
cctx.drvflags |= SLBT_DRIVER_INFO;
|
|
|
173b54 |
break;
|
|
|
173b54 |
|
|
|
c1f216 |
case TAG_CONFIG:
|
|
|
c1f216 |
cctx.drvflags |= SLBT_DRIVER_OUTPUT_CONFIG;
|
|
|
c1f216 |
break;
|
|
|
c1f216 |
|
|
|
6f4115 |
case TAG_DUMPMACHINE:
|
|
|
6f4115 |
cctx.drvflags |= SLBT_DRIVER_OUTPUT_MACHINE;
|
|
|
6f4115 |
break;
|
|
|
6f4115 |
|
|
|
fea1b8 |
case TAG_DEBUG:
|
|
|
fea1b8 |
cctx.drvflags |= SLBT_DRIVER_DEBUG;
|
|
|
fea1b8 |
break;
|
|
|
d03fbc |
|
|
|
d03fbc |
case TAG_FEATURES:
|
|
|
d03fbc |
cctx.drvflags |= SLBT_DRIVER_FEATURES;
|
|
|
d03fbc |
break;
|
|
|
6376f0 |
|
|
|
0a9bff |
case TAG_LEGABITS:
|
|
|
0a9bff |
if (!entry->arg)
|
|
|
0a9bff |
cctx.drvflags |= SLBT_DRIVER_LEGABITS;
|
|
|
0a9bff |
|
|
|
0a9bff |
else if (!strcmp("enabled",entry->arg))
|
|
|
0a9bff |
cctx.drvflags |= SLBT_DRIVER_LEGABITS;
|
|
|
0a9bff |
|
|
|
0a9bff |
else
|
|
|
0a9bff |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_LEGABITS;
|
|
|
0a9bff |
|
|
|
614d85 |
break;
|
|
|
614d85 |
|
|
|
34988f |
case TAG_CCWRAP:
|
|
|
34988f |
cctx.ccwrap = entry->arg;
|
|
|
34988f |
break;
|
|
|
34988f |
|
|
|
fbda3a |
case TAG_IMPLIB:
|
|
|
fbda3a |
if (!strcmp("idata",entry->arg)) {
|
|
|
fbda3a |
cctx.drvflags |= SLBT_DRIVER_IMPLIB_IDATA;
|
|
|
fbda3a |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_IMPLIB_DSOMETA;
|
|
|
fbda3a |
|
|
|
fbda3a |
} else if (!strcmp("never",entry->arg)) {
|
|
|
fbda3a |
cctx.drvflags |= SLBT_DRIVER_IMPLIB_DSOMETA;
|
|
|
fbda3a |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_IMPLIB_IDATA;
|
|
|
fbda3a |
}
|
|
|
fbda3a |
|
|
|
fbda3a |
break;
|
|
|
fbda3a |
|
|
|
6376f0 |
case TAG_WARNINGS:
|
|
|
6376f0 |
if (!strcmp("all",entry->arg))
|
|
|
1142bf |
cctx.warnings = SLBT_WARNING_LEVEL_ALL;
|
|
|
6376f0 |
|
|
|
6376f0 |
else if (!strcmp("error",entry->arg))
|
|
|
1142bf |
cctx.warnings = SLBT_WARNING_LEVEL_ERROR;
|
|
|
6376f0 |
|
|
|
6376f0 |
else if (!strcmp("none",entry->arg))
|
|
|
1142bf |
cctx.warnings = SLBT_WARNING_LEVEL_NONE;
|
|
|
6376f0 |
break;
|
|
|
40fabb |
|
|
|
2bc175 |
case TAG_ANNOTATE:
|
|
|
2bc175 |
if (!strcmp("always",entry->arg)) {
|
|
|
2bc175 |
cctx.drvflags |= SLBT_DRIVER_ANNOTATE_ALWAYS;
|
|
|
2bc175 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_NEVER;
|
|
|
2bc175 |
|
|
|
2bc175 |
} else if (!strcmp("never",entry->arg)) {
|
|
|
2bc175 |
cctx.drvflags |= SLBT_DRIVER_ANNOTATE_NEVER;
|
|
|
2bc175 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_ALWAYS;
|
|
|
2bc175 |
|
|
|
2bc175 |
} else if (!strcmp("minimal",entry->arg)) {
|
|
|
2bc175 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_ANNOTATE_FULL;
|
|
|
2bc175 |
|
|
|
2bc175 |
} else if (!strcmp("full",entry->arg)) {
|
|
|
2bc175 |
cctx.drvflags |= SLBT_DRIVER_ANNOTATE_FULL;
|
|
|
2bc175 |
}
|
|
|
2bc175 |
|
|
|
2bc175 |
break;
|
|
|
2bc175 |
|
|
|
40fabb |
case TAG_DEPS:
|
|
|
40fabb |
cctx.drvflags |= SLBT_DRIVER_DEPS;
|
|
|
40fabb |
break;
|
|
|
40fabb |
|
|
|
398419 |
case TAG_SILENT:
|
|
|
398419 |
cctx.drvflags |= SLBT_DRIVER_SILENT;
|
|
|
398419 |
break;
|
|
|
25956b |
|
|
|
25956b |
case TAG_VERBOSE:
|
|
|
25956b |
cctx.drvflags |= SLBT_DRIVER_VERBOSE;
|
|
|
25956b |
break;
|
|
|
b83b64 |
|
|
|
db67ad |
case TAG_HOST:
|
|
|
db67ad |
cctx.host.host = entry->arg;
|
|
|
771899 |
cfgmeta_host = cfgexplicit;
|
|
|
db67ad |
break;
|
|
|
db67ad |
|
|
|
db67ad |
case TAG_FLAVOR:
|
|
|
db67ad |
cctx.host.flavor = entry->arg;
|
|
|
db67ad |
break;
|
|
|
db67ad |
|
|
|
db67ad |
case TAG_AR:
|
|
|
db67ad |
cctx.host.ar = entry->arg;
|
|
|
d29f9c |
cfgmeta_ar = cfgexplicit;
|
|
|
db67ad |
break;
|
|
|
db67ad |
|
|
|
6bc170 |
case TAG_AS:
|
|
|
6bc170 |
cctx.host.as = entry->arg;
|
|
|
b4058c |
cfgmeta_as = cfgexplicit;
|
|
|
6bc170 |
break;
|
|
|
6bc170 |
|
|
|
b5e104 |
case TAG_NM:
|
|
|
b5e104 |
cctx.host.nm = entry->arg;
|
|
|
b5e104 |
cfgmeta_nm = cfgexplicit;
|
|
|
b5e104 |
break;
|
|
|
b5e104 |
|
|
|
db67ad |
case TAG_RANLIB:
|
|
|
db67ad |
cctx.host.ranlib = entry->arg;
|
|
|
d29f9c |
cfgmeta_ranlib = cfgexplicit;
|
|
|
db67ad |
break;
|
|
|
db67ad |
|
|
|
9a02e2 |
case TAG_WINDRES:
|
|
|
9a02e2 |
cctx.host.windres = entry->arg;
|
|
|
9a02e2 |
break;
|
|
|
9a02e2 |
|
|
|
db67ad |
case TAG_DLLTOOL:
|
|
|
db67ad |
cctx.host.dlltool = entry->arg;
|
|
|
fc8ee9 |
cfgmeta_dlltool = cfgexplicit;
|
|
|
db67ad |
break;
|
|
|
db67ad |
|
|
|
fbda3a |
case TAG_MDSO:
|
|
|
fbda3a |
cctx.host.mdso = entry->arg;
|
|
|
fbda3a |
break;
|
|
|
fbda3a |
|
|
|
b83b64 |
case TAG_OUTPUT:
|
|
|
b83b64 |
cctx.output = entry->arg;
|
|
|
b83b64 |
break;
|
|
|
4f1b20 |
|
|
|
bfa8ca |
case TAG_SHREXT:
|
|
|
bfa8ca |
cctx.shrext = entry->arg;
|
|
|
bfa8ca |
break;
|
|
|
bfa8ca |
|
|
|
9c664d |
case TAG_RPATH:
|
|
|
9c664d |
cctx.rpath = entry->arg;
|
|
|
9c664d |
break;
|
|
|
9c664d |
|
|
|
17e18a |
case TAG_SYSROOT:
|
|
|
17e18a |
cctx.sysroot = entry->arg;
|
|
|
17e18a |
break;
|
|
|
17e18a |
|
|
|
9aa1f4 |
case TAG_RELEASE:
|
|
|
9aa1f4 |
cctx.release = entry->arg;
|
|
|
9aa1f4 |
break;
|
|
|
9aa1f4 |
|
|
|
05ca7e |
case TAG_DLOPEN:
|
|
|
9da202 |
case TAG_DLPREOPEN:
|
|
|
9da202 |
ndlopen++;
|
|
|
9da202 |
break;
|
|
|
9da202 |
|
|
|
56f236 |
case TAG_STATIC_LIBTOOL_LIBS:
|
|
|
56f236 |
cctx.drvflags |= SLBT_DRIVER_STATIC_LIBTOOL_LIBS;
|
|
|
56f236 |
break;
|
|
|
56f236 |
|
|
|
916050 |
case TAG_EXPORT_DYNAMIC:
|
|
|
916050 |
cctx.drvflags |= SLBT_DRIVER_EXPORT_DYNAMIC;
|
|
|
916050 |
break;
|
|
|
916050 |
|
|
|
21bb4b |
case TAG_EXPSYMS_FILE:
|
|
|
161c3d |
cctx.expsyms = entry->arg;
|
|
|
873ecb |
break;
|
|
|
873ecb |
|
|
|
21bb4b |
case TAG_EXPSYMS_REGEX:
|
|
|
73ca78 |
cctx.regex = entry->arg;
|
|
|
73ca78 |
break;
|
|
|
73ca78 |
|
|
|
5a9161 |
case TAG_VERSION_INFO:
|
|
|
5a9161 |
cctx.verinfo.verinfo = entry->arg;
|
|
|
5a9161 |
break;
|
|
|
5a9161 |
|
|
|
cd3d41 |
case TAG_VERSION_NUMBER:
|
|
|
cd3d41 |
cctx.verinfo.vernumber = entry->arg;
|
|
|
cd3d41 |
break;
|
|
|
cd3d41 |
|
|
|
4df790 |
case TAG_TARGET:
|
|
|
4df790 |
cctx.target = entry->arg;
|
|
|
4df790 |
break;
|
|
|
4df790 |
|
|
|
4f1b20 |
case TAG_PREFER_PIC:
|
|
|
4f1b20 |
cctx.drvflags |= SLBT_DRIVER_PRO_PIC;
|
|
|
4f1b20 |
break;
|
|
|
4f1b20 |
|
|
|
4f1b20 |
case TAG_PREFER_NON_PIC:
|
|
|
4f1b20 |
cctx.drvflags |= SLBT_DRIVER_ANTI_PIC;
|
|
|
4f1b20 |
break;
|
|
|
9c25c7 |
|
|
|
93b62c |
case TAG_NO_UNDEFINED:
|
|
|
93b62c |
cctx.drvflags |= SLBT_DRIVER_NO_UNDEFINED;
|
|
|
93b62c |
break;
|
|
|
93b62c |
|
|
|
a943fc |
case TAG_MODULE:
|
|
|
a943fc |
cctx.drvflags |= SLBT_DRIVER_MODULE;
|
|
|
a943fc |
break;
|
|
|
a943fc |
|
|
|
f7645c |
case TAG_ALL_STATIC:
|
|
|
f7645c |
cctx.drvflags |= SLBT_DRIVER_ALL_STATIC;
|
|
|
f7645c |
break;
|
|
|
f7645c |
|
|
|
0e609b |
case TAG_DISABLE_STATIC:
|
|
|
89f5ab |
cmdnostatic = entry;
|
|
|
0e609b |
break;
|
|
|
0e609b |
|
|
|
f5fa4c |
case TAG_DISABLE_SHARED:
|
|
|
89f5ab |
cmdnoshared = entry;
|
|
|
f5fa4c |
break;
|
|
|
f5fa4c |
|
|
|
68f313 |
case TAG_AVOID_VERSION:
|
|
|
68f313 |
cctx.drvflags |= SLBT_DRIVER_AVOID_VERSION;
|
|
|
68f313 |
break;
|
|
|
68f313 |
|
|
|
9c25c7 |
case TAG_SHARED:
|
|
|
89f5ab |
cmdshared = entry;
|
|
|
b48cb7 |
cctx.drvflags |= SLBT_DRIVER_PREFER_SHARED;
|
|
|
9c25c7 |
break;
|
|
|
9c25c7 |
|
|
|
9c25c7 |
case TAG_STATIC:
|
|
|
89f5ab |
cmdstatic = entry;
|
|
|
b48cb7 |
cctx.drvflags |= SLBT_DRIVER_PREFER_STATIC;
|
|
|
9c25c7 |
break;
|
|
|
5e0269 |
|
|
|
5e0269 |
case TAG_WEAK:
|
|
|
5e0269 |
break;
|
|
|
9ca8c4 |
}
|
|
|
1379f7 |
}
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
c5ee86 |
/* enable both shared and static targets by default as appropriate */
|
|
|
c5ee86 |
if (!(cctx.drvflags & SLBT_DRIVER_HEURISTICS)) {
|
|
|
c5ee86 |
if (!cmdnoshared)
|
|
|
c5ee86 |
cctx.drvflags |= SLBT_DRIVER_SHARED;
|
|
|
c5ee86 |
|
|
|
c5ee86 |
if (!cmdnostatic)
|
|
|
c5ee86 |
cctx.drvflags |= SLBT_DRIVER_STATIC;
|
|
|
c5ee86 |
}
|
|
|
c5ee86 |
|
|
|
89f5ab |
/* incompatible command-line arguments? */
|
|
|
89f5ab |
if (cmdstatic && cmdshared)
|
|
|
89f5ab |
return slbt_driver_fail_incompatible_args(
|
|
|
89f5ab |
fdctx->fderr,
|
|
|
89f5ab |
cctx.drvflags,
|
|
|
89f5ab |
meta,program,
|
|
|
89f5ab |
"-static",
|
|
|
89f5ab |
"-shared");
|
|
|
89f5ab |
|
|
|
89f5ab |
if (cmdstatic && cmdnostatic)
|
|
|
89f5ab |
return slbt_driver_fail_incompatible_args(
|
|
|
89f5ab |
fdctx->fderr,
|
|
|
89f5ab |
cctx.drvflags,
|
|
|
89f5ab |
meta,program,
|
|
|
89f5ab |
"-static",
|
|
|
89f5ab |
"--disable-static");
|
|
|
89f5ab |
|
|
|
89f5ab |
if (cmdshared && cmdnoshared)
|
|
|
89f5ab |
return slbt_driver_fail_incompatible_args(
|
|
|
89f5ab |
fdctx->fderr,
|
|
|
89f5ab |
cctx.drvflags,
|
|
|
89f5ab |
meta,program,
|
|
|
89f5ab |
"-shared",
|
|
|
89f5ab |
"--disable-shared");
|
|
|
89f5ab |
|
|
|
89f5ab |
if (cmdnostatic && cmdnoshared)
|
|
|
89f5ab |
return slbt_driver_fail_incompatible_args(
|
|
|
89f5ab |
fdctx->fderr,
|
|
|
89f5ab |
cctx.drvflags,
|
|
|
89f5ab |
meta,program,
|
|
|
89f5ab |
"--disable-static",
|
|
|
89f5ab |
"--disable-shared");
|
|
|
89f5ab |
|
|
|
89f5ab |
/* -static? */
|
|
|
89f5ab |
if (cmdstatic) {
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_STATIC;
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
|
|
|
89f5ab |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
|
|
|
89f5ab |
}
|
|
|
89f5ab |
|
|
|
89f5ab |
/* shared? */
|
|
|
89f5ab |
if (cmdshared) {
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_SHARED;
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
|
|
|
89f5ab |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_SHARED;
|
|
|
89f5ab |
}
|
|
|
89f5ab |
|
|
|
005b65 |
/* -disable-static? */
|
|
|
89f5ab |
if (cmdnostatic) {
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_DISABLE_STATIC;
|
|
|
005b65 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
|
|
|
89f5ab |
}
|
|
|
005b65 |
|
|
|
005b65 |
/* -disable-shared? */
|
|
|
89f5ab |
if (cmdnoshared) {
|
|
|
89f5ab |
cctx.drvflags |= SLBT_DRIVER_DISABLE_SHARED;
|
|
|
005b65 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
|
|
|
89f5ab |
}
|
|
|
005b65 |
|
|
|
caf7d0 |
/* debug: raw argument vector */
|
|
|
caf7d0 |
if (cctx.drvflags & SLBT_DRIVER_DEBUG)
|
|
|
d4c3e3 |
slbt_output_raw_vector(
|
|
|
d4c3e3 |
fdctx->fderr,argv,envp,
|
|
|
d4c3e3 |
(cctx.drvflags & SLBT_DRIVER_ANNOTATE_NEVER)
|
|
|
d4c3e3 |
? 0 : isatty(fdctx->fderr));
|
|
|
caf7d0 |
|
|
|
9b5eec |
/* -o in install mode means USER */
|
|
|
9b5eec |
if ((cctx.mode == SLBT_MODE_INSTALL) && cctx.output) {
|
|
|
9b5eec |
cctx.user = cctx.output;
|
|
|
9b5eec |
cctx.output = 0;
|
|
|
9b5eec |
}
|
|
|
9b5eec |
|
|
|
c1f216 |
/* config mode */
|
|
|
c1f216 |
if (cctx.drvflags & SLBT_DRIVER_OUTPUT_CONFIG)
|
|
|
c1f216 |
cctx.mode = SLBT_MODE_CONFIG;
|
|
|
c1f216 |
|
|
|
3c1679 |
/* info mode */
|
|
|
c57816 |
if (cctx.drvflags & (SLBT_DRIVER_INFO | SLBT_DRIVER_FEATURES))
|
|
|
3c1679 |
cctx.mode = SLBT_MODE_INFO;
|
|
|
3c1679 |
|
|
|
a9abe3 |
/* --tag */
|
|
|
a9abe3 |
if (cctx.mode == SLBT_MODE_COMPILE)
|
|
|
a9abe3 |
if (cctx.tag == SLBT_TAG_UNKNOWN)
|
|
|
a9abe3 |
cctx.tag = SLBT_TAG_CC;
|
|
|
a9abe3 |
|
|
|
e2b582 |
/* dlopen/dlpreopen: first vector member is a virtual archive */
|
|
|
e2b582 |
if (ndlopen)
|
|
|
e2b582 |
ndlopen++;
|
|
|
e2b582 |
|
|
|
c778cc |
/* driver context */
|
|
|
9da202 |
if (!(ctx = slbt_driver_ctx_alloc(fdctx,&cctx,&sargv,objlistv,envp,ndlopen)))
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(0,meta);
|
|
|
38b351 |
|
|
|
38b351 |
/* ctx */
|
|
|
38b351 |
ctx->ctx.program = program;
|
|
|
38b351 |
ctx->ctx.cctx = &ctx->cctx;
|
|
|
38b351 |
|
|
|
38b351 |
ctx->cctx.targv = sargv.targv;
|
|
|
38b351 |
ctx->cctx.cargv = sargv.cargv;
|
|
|
53c651 |
ctx->meta = meta;
|
|
|
9ca8c4 |
|
|
|
499a71 |
/* heuristics */
|
|
|
499a71 |
if (cctx.drvflags & SLBT_DRIVER_HEURISTICS) {
|
|
|
38b351 |
if (slbt_get_lconf_flags(&ctx->ctx,lconf,&lflags) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
499a71 |
|
|
|
771899 |
if (ctx->cctx.host.host && !cfgmeta_host)
|
|
|
771899 |
cfgmeta_host = cfglconf;
|
|
|
771899 |
|
|
|
d29f9c |
if (ctx->cctx.host.ar && !cfgmeta_ar)
|
|
|
d29f9c |
cfgmeta_ar = cfglconf;
|
|
|
d29f9c |
|
|
|
b4058c |
if (ctx->cctx.host.as && !cfgmeta_as)
|
|
|
b4058c |
cfgmeta_as = cfglconf;
|
|
|
b4058c |
|
|
|
b5e104 |
if (ctx->cctx.host.nm && !cfgmeta_nm)
|
|
|
b5e104 |
cfgmeta_nm = cfglconf;
|
|
|
b5e104 |
|
|
|
d29f9c |
if (ctx->cctx.host.ranlib && !cfgmeta_ranlib)
|
|
|
d29f9c |
cfgmeta_ranlib = cfglconf;
|
|
|
d29f9c |
|
|
|
fc8ee9 |
if (ctx->cctx.host.dlltool && !cfgmeta_dlltool)
|
|
|
fc8ee9 |
cfgmeta_dlltool = cfglconf;
|
|
|
fc8ee9 |
|
|
|
9582b2 |
if (cmdnoshared)
|
|
|
9582b2 |
lflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
|
|
|
9582b2 |
|
|
|
c9788a |
if (cmdnostatic)
|
|
|
c9788a |
if (lflags & SLBT_DRIVER_DISABLE_SHARED)
|
|
|
c9788a |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_DISABLE_STATIC;
|
|
|
c9788a |
|
|
|
499a71 |
cctx.drvflags |= lflags;
|
|
|
89f5ab |
|
|
|
499a71 |
/* -disable-static? */
|
|
|
499a71 |
if (cctx.drvflags & SLBT_DRIVER_DISABLE_STATIC)
|
|
|
499a71 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_STATIC;
|
|
|
499a71 |
|
|
|
499a71 |
/* -disable-shared? */
|
|
|
499a71 |
if (cctx.drvflags & SLBT_DRIVER_DISABLE_SHARED)
|
|
|
499a71 |
cctx.drvflags &= ~(uint64_t)SLBT_DRIVER_SHARED;
|
|
|
499a71 |
|
|
|
499a71 |
ctx->cctx.drvflags = cctx.drvflags;
|
|
|
499a71 |
}
|
|
|
499a71 |
|
|
|
46ea99 |
/* host params */
|
|
|
11e277 |
if (slbt_init_host_params(
|
|
|
11e277 |
&ctx->ctx,
|
|
|
11e277 |
&ctx->cctx,
|
|
|
11e277 |
&ctx->host,
|
|
|
11e277 |
&ctx->cctx.host,
|
|
|
d29f9c |
&ctx->cctx.cfgmeta,
|
|
|
771899 |
cfgmeta_host,
|
|
|
d29f9c |
cfgmeta_ar,
|
|
|
b4058c |
cfgmeta_as,
|
|
|
b5e104 |
cfgmeta_nm,
|
|
|
fc8ee9 |
cfgmeta_ranlib,
|
|
|
fc8ee9 |
cfgmeta_dlltool))
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
46ea99 |
|
|
|
261127 |
/* host tool arguments */
|
|
|
261127 |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.ar,&ctx->host.ar_argv) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
261127 |
|
|
|
b5e104 |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.nm,&ctx->host.nm_argv) < 0)
|
|
|
b5e104 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
b5e104 |
|
|
|
261127 |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.ranlib,&ctx->host.ranlib_argv) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
261127 |
|
|
|
ba9228 |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.as,&ctx->host.as_argv) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
ba9228 |
|
|
|
94868f |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.dlltool,&ctx->host.dlltool_argv) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
94868f |
|
|
|
94868f |
if (slbt_driver_parse_tool_argv(ctx->cctx.host.mdso,&ctx->host.mdso_argv) < 0)
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
94868f |
|
|
|
11e277 |
/* flavor settings */
|
|
|
11e277 |
slbt_init_flavor_settings(
|
|
|
11e277 |
&ctx->cctx,0,
|
|
|
11e277 |
&ctx->cctx.settings);
|
|
|
11e277 |
|
|
|
af7db9 |
/* ldpath */
|
|
|
38b351 |
if (slbt_init_ldrpath(&ctx->cctx,&ctx->cctx.host))
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
af7db9 |
|
|
|
5a9161 |
/* version info */
|
|
|
38b351 |
if (slbt_init_version_info(ctx,&ctx->cctx.verinfo))
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
5a9161 |
|
|
|
f8e27e |
/* link params */
|
|
|
f8e27e |
if (cctx.mode == SLBT_MODE_LINK)
|
|
|
38b351 |
if (slbt_init_link_params(ctx))
|
|
|
ea4137 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
f8e27e |
|
|
|
9da202 |
/* dlpreopen */
|
|
|
9da202 |
if ((dlopenv = ctx->dlopenv)) {
|
|
|
9da202 |
for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
|
|
|
9da202 |
if (entry->fopt) {
|
|
|
9da202 |
switch (entry->tag) {
|
|
|
e47cd7 |
case TAG_DLOPEN:
|
|
|
a07095 |
if (!strcmp(entry->arg,"self")) {
|
|
|
a07095 |
ctx->cctx.drvflags |= SLBT_DRIVER_DLOPEN_FORCE;
|
|
|
a07095 |
|
|
|
a07095 |
} else if (!strcmp(entry->arg,"force")) {
|
|
|
a07095 |
ctx->cctx.drvflags |= SLBT_DRIVER_DLOPEN_FORCE;
|
|
|
a07095 |
|
|
|
a07095 |
} else {
|
|
|
a07095 |
*dlopenv++ = entry;
|
|
|
a07095 |
}
|
|
|
a07095 |
|
|
|
e47cd7 |
break;
|
|
|
e47cd7 |
|
|
|
9da202 |
case TAG_DLPREOPEN:
|
|
|
8ef9e1 |
if (!strcmp(entry->arg,"self")) {
|
|
|
8ef9e1 |
ctx->cctx.drvflags |= SLBT_DRIVER_DLPREOPEN_SELF;
|
|
|
8ef9e1 |
|
|
|
8ef9e1 |
} else if (!strcmp(entry->arg,"force")) {
|
|
|
8ef9e1 |
ctx->cctx.drvflags |= SLBT_DRIVER_DLPREOPEN_FORCE;
|
|
|
8ef9e1 |
|
|
|
8ef9e1 |
} else {
|
|
|
a07095 |
*dlopenv++ = entry;
|
|
|
8ef9e1 |
}
|
|
|
9da202 |
|
|
|
a07095 |
break;
|
|
|
a07095 |
|
|
|
9da202 |
default:
|
|
|
9da202 |
break;
|
|
|
9da202 |
}
|
|
|
9da202 |
}
|
|
|
9da202 |
}
|
|
|
9da202 |
}
|
|
|
9da202 |
|
|
|
8ef9e1 |
/* -dlopen & -dlpreopen semantic validation */
|
|
|
8ef9e1 |
uint64_t fmask;
|
|
|
8ef9e1 |
|
|
|
8ef9e1 |
fmask = SLBT_DRIVER_DLOPEN_SELF | SLBT_DRIVER_DLPREOPEN_SELF;
|
|
|
8ef9e1 |
fmask |= SLBT_DRIVER_DLOPEN_FORCE | SLBT_DRIVER_DLPREOPEN_FORCE;
|
|
|
8ef9e1 |
|
|
|
8ef9e1 |
if (ctx->cctx.libname && (cctx.drvflags & fmask)) {
|
|
|
8ef9e1 |
slbt_dprintf(ctx->fdctx.fderr,
|
|
|
8ef9e1 |
"%s: error: -dlopen/-dlpreopen: "
|
|
|
8ef9e1 |
"the special 'self' and 'force' arguments "
|
|
|
8ef9e1 |
"may only be used when linking a program.\n",
|
|
|
8ef9e1 |
ctx->ctx.program);
|
|
|
8ef9e1 |
|
|
|
8ef9e1 |
return slbt_lib_get_driver_ctx_fail(&ctx->ctx,0);
|
|
|
8ef9e1 |
}
|
|
|
8ef9e1 |
|
|
|
9da202 |
/* all ready */
|
|
|
9ca8c4 |
*pctx = &ctx->ctx;
|
|
|
38b351 |
|
|
|
38b351 |
return 0;
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
8f60d4 |
|
|
|
ea4137 |
static void slbt_lib_free_driver_ctx_impl(struct slbt_driver_ctx_alloc * ictx)
|
|
|
9ca8c4 |
{
|
|
|
6beda1 |
struct slbt_error_info ** perr;
|
|
|
6beda1 |
struct slbt_error_info * erri;
|
|
|
a126a7 |
struct slbt_obj_list * objlistp;
|
|
|
6beda1 |
|
|
|
6beda1 |
for (perr=ictx->ctx.errinfp; *perr; perr++) {
|
|
|
6beda1 |
erri = *perr;
|
|
|
6beda1 |
|
|
|
6beda1 |
if (erri->eany && (erri->esyscode == ENOENT))
|
|
|
6beda1 |
free(erri->eany);
|
|
|
6beda1 |
}
|
|
|
6beda1 |
|
|
|
f8e27e |
if (ictx->ctx.libname)
|
|
|
f8e27e |
free(ictx->ctx.libname);
|
|
|
f8e27e |
|
|
|
9da202 |
if (ictx->ctx.dlopenv)
|
|
|
9da202 |
free(ictx->ctx.dlopenv);
|
|
|
9da202 |
|
|
|
6ab3f1 |
if (ictx->ctx.lconf.addr)
|
|
|
6ab3f1 |
munmap(
|
|
|
6ab3f1 |
ictx->ctx.lconf.addr,
|
|
|
6ab3f1 |
ictx->ctx.lconf.size);
|
|
|
6ab3f1 |
|
|
|
a2aa78 |
if (ictx->ctx.lconfctx)
|
|
|
a2aa78 |
slbt_lib_free_txtfile_ctx(ictx->ctx.lconfctx);
|
|
|
a2aa78 |
|
|
|
a126a7 |
for (objlistp=ictx->ctx.objlistv; objlistp->name; objlistp++) {
|
|
|
a126a7 |
free(objlistp->objv);
|
|
|
a126a7 |
free(objlistp->addr);
|
|
|
a126a7 |
}
|
|
|
a126a7 |
|
|
|
a126a7 |
free(ictx->ctx.objlistv);
|
|
|
a126a7 |
|
|
|
0cbb20 |
free(ictx->ctx.dargs);
|
|
|
0cbb20 |
free(ictx->ctx.dargv);
|
|
|
0cbb20 |
free(ictx->ctx.targv);
|
|
|
0cbb20 |
|
|
|
52556c |
slbt_free_host_params(&ictx->ctx.host);
|
|
|
77b97b |
slbt_free_host_params(&ictx->ctx.ahost);
|
|
|
53c651 |
argv_free(ictx->ctx.meta);
|
|
|
a126a7 |
|
|
|
9ca8c4 |
free(ictx);
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
|
|
|
8f60d4 |
|
|
|
ea4137 |
void slbt_lib_free_driver_ctx(struct slbt_driver_ctx * ctx)
|
|
|
9ca8c4 |
{
|
|
|
9ca8c4 |
struct slbt_driver_ctx_alloc * ictx;
|
|
|
9ca8c4 |
uintptr_t addr;
|
|
|
9ca8c4 |
|
|
|
9ca8c4 |
if (ctx) {
|
|
|
a13661 |
addr = (uintptr_t)ctx - offsetof(struct slbt_driver_ctx_impl,ctx);
|
|
|
a13661 |
addr = addr - offsetof(struct slbt_driver_ctx_alloc,ctx);
|
|
|
9ca8c4 |
ictx = (struct slbt_driver_ctx_alloc *)addr;
|
|
|
ea4137 |
slbt_lib_free_driver_ctx_impl(ictx);
|
|
|
9ca8c4 |
}
|
|
|
9ca8c4 |
}
|
|
|
a313a4 |
|
|
|
1f2c01 |
|
|
|
f0270a |
const struct slbt_source_version * slbt_api_source_version(void)
|
|
|
9f24d2 |
{
|
|
|
9f24d2 |
return &slbt_src_version;
|
|
|
9f24d2 |
}
|
|
|
a82cc2 |
|
|
|
8f60d4 |
|
|
|
ea4137 |
int slbt_lib_get_driver_fdctx(
|
|
|
a82cc2 |
const struct slbt_driver_ctx * dctx,
|
|
|
a82cc2 |
struct slbt_fd_ctx * fdctx)
|
|
|
a82cc2 |
{
|
|
|
a82cc2 |
struct slbt_driver_ctx_impl * ictx;
|
|
|
a82cc2 |
|
|
|
a82cc2 |
ictx = slbt_get_driver_ictx(dctx);
|
|
|
a82cc2 |
|
|
|
a82cc2 |
fdctx->fdin = ictx->fdctx.fdin;
|
|
|
a82cc2 |
fdctx->fdout = ictx->fdctx.fdout;
|
|
|
a82cc2 |
fdctx->fderr = ictx->fdctx.fderr;
|
|
|
a82cc2 |
fdctx->fdlog = ictx->fdctx.fdlog;
|
|
|
ca72f5 |
fdctx->fdcwd = ictx->fdctx.fdcwd;
|
|
|
ca72f5 |
fdctx->fddst = ictx->fdctx.fddst;
|
|
|
a82cc2 |
|
|
|
a82cc2 |
return 0;
|
|
|
a82cc2 |
}
|
|
|
a82cc2 |
|
|
|
8f60d4 |
|
|
|
ea4137 |
int slbt_lib_set_driver_fdctx(
|
|
|
a82cc2 |
struct slbt_driver_ctx * dctx,
|
|
|
a82cc2 |
const struct slbt_fd_ctx * fdctx)
|
|
|
a82cc2 |
{
|
|
|
a82cc2 |
struct slbt_driver_ctx_impl * ictx;
|
|
|
a82cc2 |
|
|
|
a82cc2 |
ictx = slbt_get_driver_ictx(dctx);
|
|
|
a82cc2 |
|
|
|
a82cc2 |
ictx->fdctx.fdin = fdctx->fdin;
|
|
|
a82cc2 |
ictx->fdctx.fdout = fdctx->fdout;
|
|
|
a82cc2 |
ictx->fdctx.fderr = fdctx->fderr;
|
|
|
a82cc2 |
ictx->fdctx.fdlog = fdctx->fdlog;
|
|
|
ca72f5 |
ictx->fdctx.fdcwd = fdctx->fdcwd;
|
|
|
ca72f5 |
ictx->fdctx.fddst = fdctx->fddst;
|
|
|
a82cc2 |
|
|
|
a82cc2 |
return 0;
|
|
|
a82cc2 |
}
|