mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 04:49:33 -10:00
Print the -v banner on stderr and link with -version_details
ld-prime writes everything -v prints, its version banner and then the library and framework search paths, on stderr and leaves stdout alone; -v with nothing to link prints the banner and exits 0, whatever else is given. -version_details prints its JSON on stdout and, with nothing to link, exits 0; with inputs it does not stop there but prints the search paths as -v does (without the banner) and links. mold printed the banner on stdout and exited at -version_details wherever it stood. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3098b2c41e
commit
085d25033d
12 files changed
+77
-36
No files matched your search
+25
-14
@@ -23,10 +23,16 @@ use crate::util::{display, os_str, page_align};
|
||||
/// number (Xcode 26.6 ships ld-1267).
|
||||
pub const LD64_COMPAT_VERSION: &str = "1267";
|
||||
|
||||
/// Prints the -v banner. ld-prime gives its own on stderr; mold's goes
|
||||
/// to stdout, as mold's does on ELF.
|
||||
/// Prints the -v banner on stderr, where ld-prime prints its own.
|
||||
pub fn print_version() {
|
||||
println!("mold-macho {} (compatible with Apple ld64)", env!("CARGO_PKG_VERSION"));
|
||||
eprintln!("mold-macho {} (compatible with Apple ld64)", env!("CARGO_PKG_VERSION"));
|
||||
}
|
||||
|
||||
/// Prints the -version_details JSON on stdout, as ld-prime does.
|
||||
pub fn print_version_details() {
|
||||
println!(
|
||||
"{{\n\t\"version\": \"{LD64_COMPAT_VERSION}\",\n\t\"architectures\": [\n\t\t\"arm64\",\n\t\t\"x86_64\"\n\t]\n}}"
|
||||
);
|
||||
}
|
||||
|
||||
/// An input in command line order. Paths keep the bytes they were given
|
||||
@@ -181,6 +187,9 @@ pub struct Args {
|
||||
pub no_standard_dirs: bool,
|
||||
/// -v: print the version and the search paths.
|
||||
pub verbose: bool,
|
||||
/// -version_details: print the linker's description in JSON and,
|
||||
/// as -v does, the search paths.
|
||||
pub version_details: bool,
|
||||
/// -x: strip non-global symbols from the output symbol table.
|
||||
pub strip_locals: bool,
|
||||
/// Fold identical functions (on by default; -no_deduplicate turns
|
||||
@@ -449,6 +458,7 @@ impl Default for Args {
|
||||
flat_namespace: false,
|
||||
no_standard_dirs: false,
|
||||
verbose: false,
|
||||
version_details: false,
|
||||
strip_locals: false,
|
||||
deduplicate: true,
|
||||
function_starts: true,
|
||||
@@ -1607,12 +1617,8 @@ pub fn parse_args(target: &TargetTraits, cmdline: &[Cow<'_, OsStr>]) -> Args {
|
||||
// also reports its LTO and TAPI versions; they are ignored.
|
||||
// We claim the ld64 version whose command line we implement
|
||||
// so that Xcode drives us exactly as it drives ld-prime.
|
||||
b"-version_details" => {
|
||||
println!(
|
||||
"{{\n\t\"version\": \"{LD64_COMPAT_VERSION}\",\n\t\"architectures\": [\n\t\t\"arm64\",\n\t\t\"x86_64\"\n\t]\n}}"
|
||||
);
|
||||
std::process::exit(0);
|
||||
}
|
||||
// With something to link, ld-prime goes on to link it.
|
||||
b"-version_details" => args.version_details = true,
|
||||
b"-noall_load" => args.all_load = false,
|
||||
b"-ObjC" => args.load_objc = true,
|
||||
b"-force_load" => args.inputs.push(InputArg::ForceLoad(path(next_arg(&mut i, name)))),
|
||||
@@ -1868,12 +1874,17 @@ pub fn parse_args(target: &TargetTraits, cmdline: &[Cow<'_, OsStr>]) -> Args {
|
||||
|
||||
// `ld -v` with nothing to link just reports the version; build
|
||||
// systems and configure scripts probe the linker that way. mold
|
||||
// does the same for -v/--version with no inputs.
|
||||
if args.verbose && args.inputs.is_empty() {
|
||||
print_version();
|
||||
std::process::exit(0);
|
||||
}
|
||||
// does the same for -v/--version with no inputs. So does
|
||||
// -version_details, unless -v comes with it.
|
||||
if args.inputs.is_empty() {
|
||||
if args.verbose {
|
||||
print_version();
|
||||
std::process::exit(0);
|
||||
}
|
||||
if args.version_details {
|
||||
print_version_details();
|
||||
std::process::exit(0);
|
||||
}
|
||||
fatal!("no object files specified");
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -36,16 +36,20 @@ const STANDARD_FRAMEWORK_DIRS: &[&str] = &["/Library/Frameworks", "/System/Libra
|
||||
|
||||
/// Settles the library and framework search paths, once the options
|
||||
/// are checked, as ld-prime does: the -L (-F) directories, then, unless
|
||||
/// -Z, the default ones (see search_dirs). -v prints the banner here,
|
||||
/// then the paths on stderr, as ld-prime does.
|
||||
/// -Z, the default ones (see search_dirs). -v prints the banner here and
|
||||
/// -version_details its JSON; then either prints the paths on stderr,
|
||||
/// as ld-prime does.
|
||||
pub fn set_search_paths<E: Target>(ctx: &mut Context<E>) {
|
||||
let args = &mut ctx.args;
|
||||
if args.verbose {
|
||||
crate::cmdline::print_version();
|
||||
}
|
||||
if args.version_details {
|
||||
crate::cmdline::print_version_details();
|
||||
}
|
||||
args.library_paths = search_dirs(args, &args.library_paths, STANDARD_LIBRARY_DIRS);
|
||||
args.framework_paths = search_dirs(args, &args.framework_paths, STANDARD_FRAMEWORK_DIRS);
|
||||
if args.verbose {
|
||||
if args.verbose || args.version_details {
|
||||
let mut out = Vec::new();
|
||||
for (title, dirs) in
|
||||
[("Library", &args.library_paths), ("Framework", &args.framework_paths)]
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ otool -l $t/lib.dylib | grep -A4 'sectname __init_offsets' | grep -q 'size 0x0*8
|
||||
# Of an older image, which keeps __mod_init_func, ld-prime runs no
|
||||
# -init function; ld64 named it in LC_ROUTINES_64, which dyld runs
|
||||
# before the other initializers, and so do we.
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
$CC --ld-path=$mold -o $t/lib2.dylib -shared $t/a.o -Wl,-init,_init -mmacosx-version-min=11.0
|
||||
[ "$($t/exe2 $t/lib2.dylib)" = 'main init ctor 1' ]
|
||||
otool -l $t/lib2.dylib | grep -q 'cmd LC_ROUTINES_64'
|
||||
|
||||
+2
-2
@@ -91,7 +91,7 @@ set_flags $t/c.o __DATA __got 2
|
||||
|
||||
# ld-prime fails an assertion on a slot a symbol names, as arm64 code
|
||||
# names the slots it loads.
|
||||
if [ $ARCH = x86_64 ] || $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if [ $ARCH = x86_64 ] || $mold -v 2>&1 | grep -q mold-macho; then
|
||||
for obj in a c; do
|
||||
$CC --ld-path=$mold -o $t/exe-$obj $t/$obj.o $t/b.o
|
||||
$t/exe-$obj > $t/out
|
||||
@@ -105,7 +105,7 @@ if [ $ARCH = x86_64 ] || $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
done
|
||||
fi
|
||||
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
for obj in a c; do
|
||||
$mold -r -arch $ARCH -o $t/r.o $t/$obj.o
|
||||
otool -l $t/r.o | grep -A9 'sectname __got$' | grep -q 'flags 0x00000000'
|
||||
|
||||
@@ -95,7 +95,7 @@ for n in a b; do
|
||||
_y_$n: .long 0
|
||||
EOF
|
||||
done
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
$mold -r -arch $ARCH -o $t/r2.o $t/da.o $t/db.o
|
||||
[ "$(sect $t/r2.o __TEXT __literal8)" = 0x0000000000000010 ]
|
||||
objdump --macho -r $t/r2.o > $t/relocs
|
||||
|
||||
@@ -45,7 +45,7 @@ int main() {
|
||||
printf("%d %d\n", tz[5], td);
|
||||
}
|
||||
EOF
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
$CC --ld-path=$mold -o $t/exe2 $t/b.o -Wl,-no_zero_fill_sections
|
||||
otool -l $t/exe2 > $t/lc2
|
||||
sect $t/lc2 __thread_bss | grep -q ' flags 0x00000011 '
|
||||
|
||||
@@ -121,7 +121,7 @@ otool -l $t/kext | grep -A10 'sectname __foo$' | grep -q 'flags 0x00000000'
|
||||
# A -r output keeps the type and the relocations, and so is pointers
|
||||
# to a later link (ld-prime names the slots in the indirect symbol
|
||||
# table instead, which no link takes as input).
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
$mold -r -arch $ARCH -o $t/r.o $t/a.o
|
||||
otool -l $t/r.o | grep -A10 'sectname __foo$' | grep -q 'flags 0x00000006'
|
||||
objdump --macho -r $t/r.o | grep -q ' _puts$'
|
||||
|
||||
@@ -49,7 +49,7 @@ not grep -q __objc_classrefs $t/lc
|
||||
|
||||
# A reference into the middle of an atom keeps its slot: ld-prime would
|
||||
# point the load at the atom's start instead.
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
class b '.quad 7'
|
||||
$CC --ld-path=$mold -o $t/exe2 $t/main.o $t/b.o -mmacosx-version-min=15.0
|
||||
$t/exe2 | grep -q '^1$'
|
||||
|
||||
@@ -84,7 +84,7 @@ grep -q "initializer pointer has no target in '/.*/$t/c.o'" $t/log4
|
||||
# So does each entry of __objc_clsrolist, the list of Swift's class_ro_t
|
||||
# records, which is an atom of its own. (ld-prime has the check, but an
|
||||
# assertion that the entry has a relocation trips first.)
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
cat <<EOF | $CC -o $t/e.o -c -xassembler -
|
||||
.section __DATA,__objc_const
|
||||
.p2align 3
|
||||
|
||||
@@ -138,7 +138,7 @@ $t/exe3 | grep -q '^5 0$'
|
||||
|
||||
# ld-prime writes an image dyld refuses for data after the template,
|
||||
# and crashes with no template left.
|
||||
if $mold -v 2> /dev/null | grep -q mold-macho; then
|
||||
if $mold -v 2>&1 | grep -q mold-macho; then
|
||||
not $CC --ld-path=$mold -o $t/exe3 $t/d.o $t/a.o \
|
||||
-Wl,-rename_section,__DATA,__thread_data,__FOO,__bar 2> $t/log
|
||||
grep -q 'thread-locals too large' $t/log
|
||||
|
||||
@@ -1,17 +1,36 @@
|
||||
#!/bin/bash
|
||||
source "$(dirname "$0")"/common.inc
|
||||
|
||||
# `ld -v` alone prints the banner and exits 0; build systems probe the
|
||||
# linker that way.
|
||||
$mold -v > $t/v.txt
|
||||
grep -q '[ms]old' $t/v.txt
|
||||
# `ld -v` alone prints the banner (on stderr) and exits 0; build
|
||||
# systems probe the linker that way.
|
||||
banner='mold-macho\|PROGRAM:ld'
|
||||
$mold -v 2> $t/v.txt
|
||||
grep "$banner" $t/v.txt
|
||||
|
||||
# Xcode runs `ld -version_details` before the first link and needs JSON
|
||||
# with an ld64 "version" and the supported "architectures".
|
||||
$mold -version_details > $t/details.json
|
||||
python3 - $t/details.json <<'EOF'
|
||||
import json, sys
|
||||
check_json() {
|
||||
python3 - $1 <<'EOF'
|
||||
import json, re, sys
|
||||
d = json.load(open(sys.argv[1]))
|
||||
assert d["version"].isdigit(), d
|
||||
assert re.fullmatch(r"\d+(\.\d+)*", d["version"]), d
|
||||
assert "arm64" in d["architectures"] and "x86_64" in d["architectures"], d
|
||||
EOF
|
||||
}
|
||||
$mold -version_details > $t/details.json
|
||||
check_json $t/details.json
|
||||
|
||||
# With nothing to link, -v wins: the banner alone, wherever
|
||||
# -version_details stands.
|
||||
$mold -version_details -v > $t/out2 2> $t/err2
|
||||
[ ! -s $t/out2 ]
|
||||
grep "$banner" $t/err2
|
||||
|
||||
# With something to link, -version_details prints the JSON and, as -v
|
||||
# does, the search paths (but no banner), then links.
|
||||
echo 'int main() { return 0; }' | $CC -o $t/a.o -c -xc -
|
||||
$CC --ld-path=$mold -o $t/exe $t/a.o -Wl,-version_details > $t/details3.json 2> $t/err3
|
||||
check_json $t/details3.json
|
||||
grep '^Library search paths:' $t/err3
|
||||
not grep "$banner" $t/err3
|
||||
$t/exe
|
||||
+9
-2
@@ -1,7 +1,12 @@
|
||||
#!/bin/bash
|
||||
source "$(dirname "$0")"/common.inc
|
||||
|
||||
$mold -v | grep '[ms]old'
|
||||
# The -v banner goes to stderr, as ld-prime's does, and stdout stays
|
||||
# empty.
|
||||
banner='mold-macho\|PROGRAM:ld'
|
||||
$mold -v > $t/out 2> $t/err
|
||||
[ ! -s $t/out ]
|
||||
grep "$banner" $t/err
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc -
|
||||
#include <stdio.h>
|
||||
@@ -11,5 +16,7 @@ int main() {
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC --ld-path=$mold -Wl,-v -o $t/exe $t/a.o | grep '[ms]old'
|
||||
$CC --ld-path=$mold -Wl,-v -o $t/exe $t/a.o > $t/out2 2> $t/err2
|
||||
[ ! -s $t/out2 ]
|
||||
grep "$banner" $t/err2
|
||||
$t/exe | grep 'Hello world'
|
||||
Reference in new issue
Block a user