summaryrefslogtreecommitdiff
path: root/src/logic/linkcmd/slbt_linkcmd_archive.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/logic/linkcmd/slbt_linkcmd_archive.c')
-rw-r--r--src/logic/linkcmd/slbt_linkcmd_archive.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/logic/linkcmd/slbt_linkcmd_archive.c b/src/logic/linkcmd/slbt_linkcmd_archive.c
new file mode 100644
index 0000000..b7c090b
--- /dev/null
+++ b/src/logic/linkcmd/slbt_linkcmd_archive.c
@@ -0,0 +1,188 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "slibtool_linkcmd_impl.h"
+#include "slibtool_mapfile_impl.h"
+#include "slibtool_metafile_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "slibtool_spawn_impl.h"
+#include "slibtool_visibility_impl.h"
+
+static int slbt_exec_link_remove_file(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * target)
+{
+ int fdcwd;
+ char * mark;
+ char * sbuf;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* remove target (if any) */
+ if (unlinkat(fdcwd,target,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* remove a previous .disabled placeholder */
+ sbuf = (slbt_get_exec_ictx(ectx))->sbuf;
+ mark = sbuf;
+ mark += sprintf(mark,"%s",target);
+ strcpy(mark,".disabled");
+
+ if (unlinkat(fdcwd,sbuf,0) && (errno != ENOENT))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ return 0;
+}
+
+
+static bool slbt_archive_is_convenience_library(int fdcwd, const char * arpath)
+{
+ int fd;
+ char laipath[PATH_MAX];
+ char * dot;
+
+ strcpy(laipath,arpath);
+ dot = strrchr(laipath,'.');
+ strcpy(dot,".lai");
+
+ if ((fd = openat(fdcwd,laipath,O_RDONLY,0)) >= 0) {
+ close(fd);
+ return false;
+ }
+
+ return true;
+}
+
+
+slbt_hidden int slbt_exec_link_create_archive(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ const char * arfilename,
+ bool fpic,
+ bool fdep)
+{
+ int fdcwd;
+ char ** argv;
+ char ** aarg;
+ char ** parg;
+ char program[PATH_MAX];
+ char output [PATH_MAX];
+ char namebuf[PATH_MAX];
+
+ /* dlopen, dlpreopen: object compilation (derived from dynamic linking) */
+ if (ectx->dlopenobj) {
+ slbt_ectx_reset_arguments(ectx);
+ slbt_reset_placeholders(ectx);
+
+ sprintf(namebuf,"%s%s",ectx->ldirname,"@ARDLOPEN@");
+
+ if (slbt_exec_link_create_library(
+ dctx,ectx,
+ namebuf,namebuf,namebuf,
+ true,fpic) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+ }
+
+ /* restore initial state */
+ slbt_ectx_reset_arguments(ectx);
+
+ /* placeholders */
+ slbt_reset_placeholders(ectx);
+
+ /* output */
+ if (slbt_snprintf(output,sizeof(output),
+ "%s",arfilename) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* tool-specific argument vector */
+ argv = (slbt_get_driver_ictx(dctx))->host.ar_argv;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* input argument adjustment */
+ aarg = ectx->altv;
+
+ if ((parg = argv)) {
+ for (; *parg; )
+ *aarg++ = *parg++;
+ } else {
+ *aarg++ = program;
+ }
+
+ *aarg++ = "-crs";
+ *aarg++ = output;
+
+ for (parg=ectx->cargv; *parg; parg++)
+ if (slbt_adjust_object_argument(*parg,fpic,!fpic,fdcwd))
+ *aarg++ = *parg;
+
+ if (ectx->dlopenobj)
+ *aarg++ = ectx->dlopenobj;
+
+ *aarg = 0;
+ ectx->argv = ectx->altv;
+
+ /* ar program */
+ if (argv) {
+ ectx->program = argv[0];
+ } else {
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.ar) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ ectx->program = program;
+ }
+
+ /* step output */
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_link(ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove old archive as needed */
+ if (slbt_exec_link_remove_file(dctx,ectx,output))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .deps */
+ if (fdep)
+ if (slbt_exec_link_create_dep_file(
+ dctx,ectx,ectx->cargv,
+ arfilename,true))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* ar spawn */
+ if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
+ return SLBT_SPAWN_ERROR(dctx);
+
+ } else if (ectx->exitcode) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ERROR);
+ }
+
+ /* input objects associated with .la archives */
+ for (parg=ectx->cargv; *parg; parg++)
+ if (slbt_adjust_wrapper_argument(
+ *parg,true,
+ dctx->cctx->settings.arsuffix))
+ if (slbt_archive_is_convenience_library(fdcwd,*parg))
+ if (slbt_util_import_archive(ectx,output,*parg))
+ return SLBT_NESTED_ERROR(dctx);
+ return 0;
+}