/* ar.c - Archive modify and extract.
- Copyright (C) 1991-2019 Free Software Foundation, Inc.
+ Copyright (C) 1991-2023 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
-#include "progress.h"
#include "getopt.h"
#include "aout/ar.h"
#include "bucomm.h"
static void move_members (bfd *, char **files_to_move);
static void replace_members
- (bfd *, char **files_to_replace, bfd_boolean quick);
+ (bfd *, char **files_to_replace, bool quick);
static void print_descr (bfd * abfd);
static void write_archive (bfd *);
static int ranlib_only (const char *archname);
/* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only
extract the COUNTED_NAME_COUNTER instance of that name. */
-static bfd_boolean counted_name_mode = 0;
+static bool counted_name_mode = 0;
static int counted_name_counter = 0;
/* Whether to truncate names of files stored in the archive. */
-static bfd_boolean ar_truncate = FALSE;
+static bool ar_truncate = false;
/* Whether to use a full file name match when searching an archive.
This is convenient for archives created by the Microsoft lib
program. */
-static bfd_boolean full_pathname = FALSE;
+static bool full_pathname = false;
/* Whether to create a "thin" archive (symbol index only -- no files). */
-static bfd_boolean make_thin_archive = FALSE;
+static bool make_thin_archive = false;
+
+#define LIBDEPS "__.LIBDEP"
+/* Text to store in the __.LIBDEP archive element for the linker to use. */
+static char * libdeps = NULL;
+static bfd * libdeps_bfd = NULL;
static int show_version = 0;
{"target", required_argument, NULL, OPTION_TARGET},
{"version", no_argument, &show_version, 1},
{"output", required_argument, NULL, OPTION_OUTPUT},
+ {"record-libdeps", required_argument, NULL, 'l'},
+ {"thin", no_argument, NULL, 'T'},
{NULL, no_argument, NULL, 0}
};
if (count == 0)
{
for (head = arch->archive_next; head; head = head->archive_next)
- {
- PROGRESS (1);
- function (head);
- }
+ function (head);
return;
}
for (; count > 0; files++, count--)
{
- bfd_boolean found = FALSE;
+ bool found = false;
match_count = 0;
for (head = arch->archive_next; head; head = head->archive_next)
{
const char * filename;
- PROGRESS (1);
/* PR binutils/15796: Once an archive element has been matched
do not match it again. If the user provides multiple same-named
parameters on the command line their intent is to match multiple
if (head->archive_pass)
continue;
- filename = head->filename;
+ filename = bfd_get_filename (head);
if (filename == NULL)
{
/* Some archive formats don't get the filenames filled in
continue;
}
- found = TRUE;
+ found = true;
function (head);
head->archive_pass = 1;
/* PR binutils/15796: Once a file has been matched, do not
}
}
\f
-bfd_boolean operation_alters_arch = FALSE;
+bool operation_alters_arch = false;
static void
usage (int help)
fprintf (s, _(" generic modifiers:\n"));
fprintf (s, _(" [c] - do not warn if the library had to be created\n"));
fprintf (s, _(" [s] - create an archive index (cf. ranlib)\n"));
+ fprintf (s, _(" [l <text> ] - specify the dependencies of this library\n"));
fprintf (s, _(" [S] - do not build a symbol table\n"));
- fprintf (s, _(" [T] - make a thin archive\n"));
+ fprintf (s, _(" [T] - deprecated, use --thin instead\n"));
fprintf (s, _(" [v] - be verbose\n"));
fprintf (s, _(" [V] - display the version number\n"));
fprintf (s, _(" @<file> - read options from <file>\n"));
fprintf (s, _(" --target=BFDNAME - specify the target object format as BFDNAME\n"));
fprintf (s, _(" --output=DIRNAME - specify the output directory for extraction operations\n"));
+ fprintf (s, _(" --record-libdeps=<text> - specify the dependencies of this library\n"));
+ fprintf (s, _(" --thin - make a thin archive\n"));
#if BFD_SUPPORTS_PLUGINS
fprintf (s, _(" optional:\n"));
fprintf (s, _(" --plugin <p> - load the specified plugin\n"));
static const char *output_filename = NULL;
static FILE *output_file = NULL;
-static bfd *output_bfd = NULL;
static void
remove_output (void)
{
if (output_filename != NULL)
{
- if (output_bfd != NULL)
- bfd_cache_close (output_bfd);
if (output_file != NULL)
fclose (output_file);
unlink_if_ordinary (output_filename);
argv = new_argv;
}
- while ((c = getopt_long (argc, argv, "hdmpqrtxlcoOVsSuvabiMNfPTDU",
+ while ((c = getopt_long (argc, argv, "hdmpqrtxl:coOVsSuvabiMNfPTDU",
long_options, NULL)) != EOF)
{
switch (c)
break;
case 'd':
operation = del;
- operation_alters_arch = TRUE;
+ operation_alters_arch = true;
break;
case 'm':
operation = move;
- operation_alters_arch = TRUE;
+ operation_alters_arch = true;
break;
case 'p':
operation = print_files;
break;
case 'q':
operation = quick_append;
- operation_alters_arch = TRUE;
+ operation_alters_arch = true;
break;
case 'r':
operation = replace;
- operation_alters_arch = TRUE;
+ operation_alters_arch = true;
break;
case 't':
operation = print_table;
operation = extract;
break;
case 'l':
+ if (libdeps != NULL)
+ fatal (_("libdeps specified more than once"));
+ libdeps = optarg;
break;
case 'c':
silent_create = 1;
display_offsets = 1;
break;
case 'V':
- show_version = TRUE;
+ show_version = true;
break;
case 's':
write_armap = 1;
mri_mode = 1;
break;
case 'N':
- counted_name_mode = TRUE;
+ counted_name_mode = true;
break;
case 'f':
- ar_truncate = TRUE;
+ ar_truncate = true;
break;
case 'P':
- full_pathname = TRUE;
+ full_pathname = true;
break;
case 'T':
- make_thin_archive = TRUE;
+ make_thin_archive = true;
break;
case 'D':
- deterministic = TRUE;
+ deterministic = true;
break;
case 'U':
- deterministic = FALSE;
+ deterministic = false;
break;
case OPTION_PLUGIN:
#if BFD_SUPPORTS_PLUGINS
ranlib_main (int argc, char **argv)
{
int arg_index, status = 0;
- bfd_boolean touch = FALSE;
+ bool touch = false;
int c;
while ((c = getopt_long (argc, argv, "DhHUvVt", long_options, NULL)) != EOF)
switch (c)
{
case 'D':
- deterministic = TRUE;
+ deterministic = true;
break;
case 'U':
- deterministic = FALSE;
+ deterministic = false;
break;
case 'h':
case 'H':
show_help = 1;
break;
case 't':
- touch = TRUE;
+ touch = true;
break;
case 'v':
case 'V':
char *inarch_filename;
int i;
-#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
#endif
-#if defined (HAVE_SETLOCALE)
setlocale (LC_CTYPE, "");
-#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
is_ranlib = 0;
}
- START_PROGRESS (program_name, 0);
-
if (bfd_init () != BFD_INIT_MAGIC)
fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
if (operation == extract && bfd_is_thin_archive (arch))
fatal (_("`x' cannot be used on thin archives."));
+ if (libdeps != NULL)
+ {
+ char **new_files;
+ bfd_size_type reclen = strlen (libdeps) + 1;
+
+ /* Create a bfd to contain the dependencies.
+ It inherits its type from arch, but we must set the type to
+ "binary" otherwise bfd_bwrite() will fail. After writing, we
+ must set the type back to default otherwise adding it to the
+ archive will fail. */
+ libdeps_bfd = bfd_create (LIBDEPS, arch);
+ if (libdeps_bfd == NULL)
+ fatal (_("Cannot create libdeps record."));
+
+ if (bfd_find_target ("binary", libdeps_bfd) == NULL)
+ fatal (_("Cannot set libdeps record type to binary."));
+
+ if (! bfd_set_format (libdeps_bfd, bfd_object))
+ fatal (_("Cannot set libdeps object format."));
+
+ if (! bfd_make_writable (libdeps_bfd))
+ fatal (_("Cannot make libdeps object writable."));
+
+ if (bfd_bwrite (libdeps, reclen, libdeps_bfd) != reclen)
+ fatal (_("Cannot write libdeps record."));
+
+ if (! bfd_make_readable (libdeps_bfd))
+ fatal (_("Cannot make libdeps object readable."));
+
+ if (bfd_find_target (plugin_target, libdeps_bfd) == NULL)
+ fatal (_("Cannot reset libdeps record type."));
+
+ /* Insert our libdeps record in 2nd slot of the list of files
+ being operated on. We shouldn't use 1st slot, but we want
+ to avoid having to search all the way to the end of an
+ archive with a large number of members at link time. */
+ new_files = xmalloc ((file_count + 2) * sizeof (*new_files));
+ if (file_count)
+ {
+ new_files[0] = files[0];
+ memcpy (new_files + 1, files, file_count * sizeof (*files));
+ }
+ new_files[file_count != 0] = LIBDEPS;
+ file_count++;
+ new_files[file_count] = NULL;
+ files = new_files;
+ }
+
switch (operation)
{
case print_table:
}
}
- END_PROGRESS (program_name);
-
xexit (0);
return 0;
}
{
bfd_nonfatal (archive_filename);
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
- {
- list_matching_formats (matching);
- free (matching);
- }
+ list_matching_formats (matching);
xexit (1);
}
next_one;
next_one = bfd_openr_next_archived_file (arch, next_one))
{
- PROGRESS (1);
*last_one = next_one;
last_one = &next_one->archive_next;
}
output_filename, base);
output_filename = base;
}
-
+
if (output_dir)
{
size_t len = strlen (output_dir);
if (verbose)
printf ("x - %s\n", output_filename);
-
+
FILE * ostream = fopen (output_filename, FOPEN_WB);
if (ostream == NULL)
{
bfd_size_type size;
struct stat buf;
+ if (preserve_dates)
+ memset (&buf, 0, sizeof (buf));
+
if (bfd_stat_arch_elt (abfd, &buf) != 0)
/* xgettext:c-format */
fatal (_("internal stat error on %s"), bfd_get_filename (abfd));
bfd *obfd;
char *old_name, *new_name;
bfd *contents_head = iarch->archive_next;
+ int tmpfd = -1;
- old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1);
- strcpy (old_name, bfd_get_filename (iarch));
- new_name = make_tempname (old_name);
+ old_name = xstrdup (bfd_get_filename (iarch));
+ new_name = make_tempname (old_name, &tmpfd);
if (new_name == NULL)
bfd_fatal (_("could not create temporary file whilst writing archive"));
output_filename = new_name;
- obfd = bfd_openw (new_name, bfd_get_target (iarch));
+ obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), tmpfd);
if (obfd == NULL)
- bfd_fatal (old_name);
-
- output_bfd = obfd;
+ {
+ close (tmpfd);
+ bfd_fatal (old_name);
+ }
bfd_set_format (obfd, bfd_archive);
obfd->flags |= BFD_ARCHIVE_FULL_PATH;
if (make_thin_archive || bfd_is_thin_archive (iarch))
- bfd_set_thin_archive (obfd, TRUE);
+ bfd_set_thin_archive (obfd, true);
if (!bfd_set_archive_head (obfd, contents_head))
bfd_fatal (old_name);
+ tmpfd = dup (tmpfd);
if (!bfd_close (obfd))
bfd_fatal (old_name);
- output_bfd = NULL;
output_filename = NULL;
/* We don't care if this fails; we might be creating the archive. */
bfd_close (iarch);
- if (smart_rename (new_name, old_name, 0) != 0)
+ if (smart_rename (new_name, old_name, tmpfd, NULL, false) != 0)
xexit (1);
free (old_name);
free (new_name);
else
{
for (; *after_bfd; after_bfd = &(*after_bfd)->archive_next)
- if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0)
+ if (FILENAME_CMP (bfd_get_filename (*after_bfd), realposname) == 0)
{
if (realpos == pos_after)
after_bfd = &(*after_bfd)->archive_next;
delete_members (bfd *arch, char **files_to_delete)
{
bfd **current_ptr_ptr;
- bfd_boolean found;
- bfd_boolean something_changed = FALSE;
+ bool found;
+ bool something_changed = false;
int match_count;
for (; *files_to_delete != NULL; ++files_to_delete)
if (!strcmp (*files_to_delete, "__.SYMDEF"))
{
- arch->has_armap = FALSE;
+ arch->has_armap = false;
write_armap = -1;
continue;
}
- found = FALSE;
+ found = false;
match_count = 0;
current_ptr_ptr = &(arch->archive_next);
while (*current_ptr_ptr)
{
if (FILENAME_CMP (normalize (*files_to_delete, arch),
- (*current_ptr_ptr)->filename) == 0)
+ bfd_get_filename (*current_ptr_ptr)) == 0)
{
++match_count;
if (counted_name_mode
}
else
{
- found = TRUE;
- something_changed = TRUE;
+ found = true;
+ something_changed = true;
if (verbose)
printf ("d - %s\n",
*files_to_delete);
{
bfd *current_ptr = *current_ptr_ptr;
if (FILENAME_CMP (normalize (*files_to_move, arch),
- current_ptr->filename) == 0)
+ bfd_get_filename (current_ptr)) == 0)
{
/* Move this file to the end of the list - first cut from
where it is. */
current_ptr_ptr = &((*current_ptr_ptr)->archive_next);
}
/* xgettext:c-format */
- fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename);
+ fatal (_("no entry %s in archive %s!"), *files_to_move,
+ bfd_get_filename (arch));
next_file:;
}
/* Ought to default to replacing in place, but this is existing practice! */
static void
-replace_members (bfd *arch, char **files_to_move, bfd_boolean quick)
+replace_members (bfd *arch, char **files_to_move, bool quick)
{
- bfd_boolean changed = FALSE;
+ bool changed = false;
bfd **after_bfd; /* New entries go after this one. */
bfd *current;
bfd **current_ptr;
/* For compatibility with existing ar programs, we
permit the same file to be added multiple times. */
if (FILENAME_CMP (normalize (*files_to_move, arch),
- normalize (current->filename, arch)) == 0
+ normalize (bfd_get_filename (current), arch)) == 0
&& current->arelt_data != NULL)
{
+ bool replaced;
if (newer_only)
{
struct stat fsbuf, asbuf;
if (bfd_stat_arch_elt (current, &asbuf) != 0)
/* xgettext:c-format */
fatal (_("internal stat error on %s"),
- current->filename);
+ bfd_get_filename (current));
if (fsbuf.st_mtime <= asbuf.st_mtime)
goto next_file;
}
after_bfd = get_pos_bfd (&arch->archive_next, pos_after,
- current->filename);
- if (ar_emul_replace (after_bfd, *files_to_move,
- target, verbose))
+ bfd_get_filename (current));
+ if (libdeps_bfd != NULL
+ && FILENAME_CMP (normalize (*files_to_move, arch),
+ LIBDEPS) == 0)
+ {
+ replaced = ar_emul_replace_bfd (after_bfd, libdeps_bfd,
+ verbose);
+ }
+ else
+ {
+ replaced = ar_emul_replace (after_bfd, *files_to_move,
+ target, verbose);
+ }
+ if (replaced)
{
/* Snip out this entry from the chain. */
*current_ptr = (*current_ptr)->archive_next;
- changed = TRUE;
+ changed = true;
}
goto next_file;
/* Add to the end of the archive. */
after_bfd = get_pos_bfd (&arch->archive_next, pos_end, NULL);
- if (ar_emul_append (after_bfd, *files_to_move, target,
- verbose, make_thin_archive))
- changed = TRUE;
+ if (libdeps_bfd != NULL
+ && FILENAME_CMP (normalize (*files_to_move, arch), LIBDEPS) == 0)
+ {
+ changed |= ar_emul_append_bfd (after_bfd, libdeps_bfd,
+ verbose, make_thin_archive);
+ }
+ else
+ {
+ changed |= ar_emul_append (after_bfd, *files_to_move, target,
+ verbose, make_thin_archive);
+ }
next_file:;
{
bfd_nonfatal (archname);
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
- {
- list_matching_formats (matching);
- free (matching);
- }
+ list_matching_formats (matching);
xexit (1);
}