forked from OSchip/llvm-project
[llvm-libtool-darwin] Add support for -arch_only
Add support for -arch_only option for llvm-libtool-darwin. This diff also adds support for accepting universal files as input and flattening them to create the required static library. Supports input universal files contaning both Mach-O object files or archives. Differences from cctools' libtool: - `-arch_only` can be specified multiple times - archives containing universal files are considered invalid (libtool allows such archives) Reviewed by jhenderson, smeenai Differential Revision: https://reviews.llvm.org/D84770
This commit is contained in:
parent
05169af5ce
commit
bd2853f799
|
@ -21,6 +21,26 @@ OPTIONS
|
||||||
--------
|
--------
|
||||||
:program:`llvm-libtool-darwin` supports the following options:
|
:program:`llvm-libtool-darwin` supports the following options:
|
||||||
|
|
||||||
|
.. option:: -arch_only <architecture>
|
||||||
|
|
||||||
|
Build a static library only for the specified `<architecture>` and ignore all
|
||||||
|
other architectures in the files.
|
||||||
|
|
||||||
|
.. option:: -color
|
||||||
|
|
||||||
|
Use colors in output.
|
||||||
|
|
||||||
|
.. option:: -D
|
||||||
|
|
||||||
|
Use zero for timestamps and UIDs/GIDs. This is set by default.
|
||||||
|
|
||||||
|
.. option:: -filelist <listfile[,dirname]>
|
||||||
|
|
||||||
|
Read input file names from `<listfile>`. File names are specified in `<listfile>`
|
||||||
|
one per line, separated only by newlines. Whitespace on a line is assumed
|
||||||
|
to be part of the filename. If the directory name, `dirname`, is also
|
||||||
|
specified then it is prepended to each file name in the `<listfile>`.
|
||||||
|
|
||||||
.. option:: -h, -help
|
.. option:: -h, -help
|
||||||
|
|
||||||
Show help and usage for this command.
|
Show help and usage for this command.
|
||||||
|
@ -30,36 +50,21 @@ OPTIONS
|
||||||
Show help and usage for this command without grouping the options
|
Show help and usage for this command without grouping the options
|
||||||
into categories.
|
into categories.
|
||||||
|
|
||||||
.. option:: -color
|
|
||||||
|
|
||||||
Use colors in output.
|
|
||||||
|
|
||||||
.. option:: -version
|
|
||||||
|
|
||||||
Display the version of this program.
|
|
||||||
|
|
||||||
.. option:: -D
|
|
||||||
|
|
||||||
Use zero for timestamps and UIDs/GIDs. This is set by default.
|
|
||||||
|
|
||||||
.. option:: -U
|
|
||||||
|
|
||||||
Use actual timestamps and UIDs/GIDs.
|
|
||||||
|
|
||||||
.. option:: -o <filename>
|
.. option:: -o <filename>
|
||||||
|
|
||||||
Specify the output file name. Must be specified exactly once.
|
Specify the output file name. Must be specified exactly once.
|
||||||
|
|
||||||
.. option:: -static
|
.. option:: -static
|
||||||
|
|
||||||
Produces a static library from the input files.
|
Produces a static library from the input files.
|
||||||
|
|
||||||
.. option:: -filelist <listfile[,dirname]>
|
.. option:: -U
|
||||||
|
|
||||||
Read input file names from `<listfile>`. File names are specified in `<listfile>`
|
Use actual timestamps and UIDs/GIDs.
|
||||||
one per line, separated only by newlines. Whitespace on a line is assumed
|
|
||||||
to be part of the filename. If the directory name, `dirname`, is also
|
.. option:: -version
|
||||||
specified then it is prepended to each file name in the `<listfile>`.
|
|
||||||
|
Display the version of this program.
|
||||||
|
|
||||||
EXIT STATUS
|
EXIT STATUS
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -0,0 +1,269 @@
|
||||||
|
## This test checks that the CPU subtype matching logic is handled correctly.
|
||||||
|
|
||||||
|
# RUN: yaml2obj %s --docnum=1 -o %t.armv6
|
||||||
|
# RUN: yaml2obj %s --docnum=2 -o %t.armv7
|
||||||
|
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t.armv6 %t.armv7 -arch_only armv7
|
||||||
|
|
||||||
|
## Check that only armv7 binary is present:
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=ARM-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
|
||||||
|
# ARM-NAMES: [[PREFIX]].armv7
|
||||||
|
|
||||||
|
## Check that only armv7 symbol is present:
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=ARM-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# ARM-SYMBOLS: Archive map
|
||||||
|
# ARM-SYMBOLS-NEXT: _armv7 in [[PREFIX]].armv7
|
||||||
|
# ARM-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## armv6.yaml
|
||||||
|
## CPUTYPE: CPU_TYPE_ARM
|
||||||
|
## CPUSUBTYPE: CPU_SUBTYPE_ARM_V6
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACE
|
||||||
|
cputype: 0x0000000C
|
||||||
|
cpusubtype: 0x00000006
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 148
|
||||||
|
flags: 0x00002000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT
|
||||||
|
cmdsize: 124
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 24
|
||||||
|
fileoff: 296
|
||||||
|
filesize: 24
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 24
|
||||||
|
offset: 0x00000128
|
||||||
|
align: 2
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: 04D04DE208009FE500008DE504D08DE21EFF2FE100000000
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 328
|
||||||
|
nsyms: 1
|
||||||
|
stroff: 340
|
||||||
|
strsize: 8
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _armv6
|
||||||
|
- ''
|
||||||
|
...
|
||||||
|
|
||||||
|
## armv7.yaml
|
||||||
|
## CPUTYPE: CPU_TYPE_ARM
|
||||||
|
## CPUSUBTYPE: CPU_SUBTYPE_ARM_V7
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACE
|
||||||
|
cputype: 0x0000000C
|
||||||
|
cpusubtype: 0x00000009
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 148
|
||||||
|
flags: 0x00002000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT
|
||||||
|
cmdsize: 124
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 10
|
||||||
|
fileoff: 280
|
||||||
|
filesize: 10
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 10
|
||||||
|
offset: 0x00000118
|
||||||
|
align: 1
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: 81B00020009001B07047
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 292
|
||||||
|
nsyms: 1
|
||||||
|
stroff: 304
|
||||||
|
strsize: 8
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 8
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _armv7
|
||||||
|
- ''
|
||||||
|
...
|
||||||
|
|
||||||
|
# RUN: yaml2obj %s --docnum=3 -o %t.x86_64
|
||||||
|
# RUN: yaml2obj %s --docnum=4 -o %t.x86_64_h
|
||||||
|
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t.x86_64 %t.x86_64_h -arch_only x86_64
|
||||||
|
|
||||||
|
## Check that only x86_64 binary is present:
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=X86-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
|
||||||
|
# X86-NAMES: [[PREFIX]].x86_64
|
||||||
|
|
||||||
|
## Check that only x86_64 symbol is present:
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=X86-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# X86-SYMBOLS: Archive map
|
||||||
|
# X86-SYMBOLS-NEXT: _x86_64 in [[PREFIX]].x86_64
|
||||||
|
# X86-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## x86_64.yaml
|
||||||
|
## CPUTYPE: CPU_TYPE_X86_64
|
||||||
|
## CPUSUBTYPE: CPU_SUBTYPE_X86_64_ALL
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x01000007
|
||||||
|
cpusubtype: 0x00000003
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 176
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 15
|
||||||
|
fileoff: 312
|
||||||
|
filesize: 15
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 15
|
||||||
|
offset: 0x00000138
|
||||||
|
align: 4
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: 554889E531C0C745FC000000005DC3
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 328
|
||||||
|
nsyms: 1
|
||||||
|
stroff: 344
|
||||||
|
strsize: 8
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _x86_64
|
||||||
|
- ''
|
||||||
|
...
|
||||||
|
|
||||||
|
## x86_64h.yaml
|
||||||
|
## CPUTYPE: CPU_TYPE_X86_64
|
||||||
|
## CPUSUBTYPE: CPU_SUBTYPE_X86_64_H
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x01000007
|
||||||
|
cpusubtype: 0x00000008
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 176
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 15
|
||||||
|
fileoff: 312
|
||||||
|
filesize: 15
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 15
|
||||||
|
offset: 0x00000138
|
||||||
|
align: 4
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: 554889E531C0C745FC000000005DC3
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 328
|
||||||
|
nsyms: 1
|
||||||
|
stroff: 344
|
||||||
|
strsize: 8
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _x86_64_h
|
||||||
|
- ''
|
||||||
|
...
|
|
@ -0,0 +1,240 @@
|
||||||
|
## This test checks that a universal file is flattened correctly.
|
||||||
|
|
||||||
|
# RUN: yaml2obj %s -o %t-universal.o
|
||||||
|
# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o
|
||||||
|
# RUN: yaml2obj %S/Inputs/input2.yaml -o %t-input2.o
|
||||||
|
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only arm64
|
||||||
|
|
||||||
|
## Check that the binary is present:
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=CHECK-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
|
||||||
|
# CHECK-NAMES: [[PREFIX]]-universal.o
|
||||||
|
|
||||||
|
## Check that symbols are present:
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=CHECK-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# CHECK-SYMBOLS: Archive map
|
||||||
|
# CHECK-SYMBOLS-NEXT: _arm64 in [[PREFIX]]-universal.o
|
||||||
|
# CHECK-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## Check that the output archive is in Darwin format:
|
||||||
|
# RUN: llvm-objdump --macho --archive-headers %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=FORMAT -DPREFIX=%basename_t.tmp -DARCHIVE=%t.lib
|
||||||
|
|
||||||
|
# FORMAT: Archive : [[ARCHIVE]]
|
||||||
|
# FORMAT-NEXT: __.SYMDEF
|
||||||
|
# FORMAT-NEXT: [[PREFIX]]-universal.o
|
||||||
|
# FORMAT-NOT: {{.}}
|
||||||
|
|
||||||
|
## Passing both a universal file and an object file:
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t-universal.o %t-input1.o -arch_only x86_64
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=BOTH-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=BOTH-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# BOTH-NAMES: [[PREFIX]]-universal.o
|
||||||
|
# BOTH-NAMES-NEXT: [[PREFIX]]-input1.o
|
||||||
|
|
||||||
|
# BOTH-SYMBOLS: Archive map
|
||||||
|
# BOTH-SYMBOLS-NEXT: _x86_64 in [[PREFIX]]-universal.o
|
||||||
|
# BOTH-SYMBOLS-NEXT: _symbol1 in [[PREFIX]]-input1.o
|
||||||
|
# BOTH-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## Passing both a universal file and an object file but filtering out the object file:
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t-universal.o %t-input1.o -arch_only arm64
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=CHECK-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=CHECK-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
## Universal file containing an archive:
|
||||||
|
# RUN: rm -f %t.ar
|
||||||
|
# RUN: llvm-ar cr %t.ar %t-input1.o %t-input2.o
|
||||||
|
# RUN: llvm-lipo %t.ar -create -output %t-fat-with-archive.o
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t-fat-with-archive.o -arch_only x86_64
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=ARCHIVE-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=ARCHIVE-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# ARCHIVE-NAMES: [[PREFIX]]-input1.o
|
||||||
|
# ARCHIVE-NAMES-NEXT: [[PREFIX]]-input2.o
|
||||||
|
|
||||||
|
# ARCHIVE-SYMBOLS: Archive map
|
||||||
|
# ARCHIVE-SYMBOLS-NEXT: _symbol1 in [[PREFIX]]-input1.o
|
||||||
|
# ARCHIVE-SYMBOLS-NEXT: _symbol2 in [[PREFIX]]-input2.o
|
||||||
|
# ARCHIVE-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## Allow arch_only to be specified more than once (pick the last one):
|
||||||
|
# RUN: llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only arm64 -arch_only x86_64
|
||||||
|
# RUN: llvm-ar t %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=DOUBLE-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
|
||||||
|
# RUN: llvm-nm --print-armap %t.lib | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=DOUBLE-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
|
||||||
|
|
||||||
|
# DOUBLE-NAMES: [[PREFIX]]-universal.o
|
||||||
|
|
||||||
|
# DOUBLE-SYMBOLS: Archive map
|
||||||
|
# DOUBLE-SYMBOLS-NEXT: _x86_64 in [[PREFIX]]-universal.o
|
||||||
|
# DOUBLE-SYMBOLS-EMPTY:
|
||||||
|
|
||||||
|
## Invalid architecture:
|
||||||
|
# RUN: not llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only arch101 2>&1 | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=INVALID-ARCH
|
||||||
|
|
||||||
|
# INVALID-ARCH: invalid architecture 'arch101': valid architecture names are
|
||||||
|
|
||||||
|
## Empty architecture:
|
||||||
|
# RUN: not llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only "" 2>&1 | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=EMPTY-ARCH
|
||||||
|
|
||||||
|
# EMPTY-ARCH: invalid architecture '': valid architecture names are
|
||||||
|
|
||||||
|
## Missing architecture:
|
||||||
|
# RUN: not llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only ppc 2>&1 | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=MISSING-ARCH
|
||||||
|
|
||||||
|
# MISSING-ARCH: error: no library created (no object files in input files matching -arch_only ppc)
|
||||||
|
|
||||||
|
## arch_only missing argument:
|
||||||
|
# RUN: not llvm-libtool-darwin -static -o %t.lib %t-universal.o -arch_only 2>&1 | \
|
||||||
|
# RUN: FileCheck %s --check-prefix=REQUIRE-ARCH
|
||||||
|
|
||||||
|
# REQUIRE-ARCH: for the --arch_only option: requires a value!
|
||||||
|
|
||||||
|
## x86_64-arm64-universal.yaml
|
||||||
|
--- !fat-mach-o
|
||||||
|
FatHeader:
|
||||||
|
magic: 0xCAFEBABE
|
||||||
|
nfat_arch: 2
|
||||||
|
FatArchs:
|
||||||
|
- cputype: 0x01000007
|
||||||
|
cpusubtype: 0x00000003
|
||||||
|
offset: 0x0000000000001000
|
||||||
|
size: 352
|
||||||
|
align: 12
|
||||||
|
- cputype: 0x0100000C
|
||||||
|
cpusubtype: 0x00000000
|
||||||
|
offset: 0x0000000000004000
|
||||||
|
size: 384
|
||||||
|
align: 14
|
||||||
|
Slices:
|
||||||
|
- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x01000007
|
||||||
|
cpusubtype: 0x00000003
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 176
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 15
|
||||||
|
fileoff: 312
|
||||||
|
filesize: 15
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 15
|
||||||
|
offset: 0x00000138
|
||||||
|
align: 4
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: 554889E531C0C745FC000000005DC3
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 328
|
||||||
|
nsyms: 1
|
||||||
|
stroff: 344
|
||||||
|
strsize: 8
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _x86_64
|
||||||
|
- ''
|
||||||
|
- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x0100000C
|
||||||
|
cpusubtype: 0x00000000
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 2
|
||||||
|
sizeofcmds: 176
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: ''
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 24
|
||||||
|
fileoff: 312
|
||||||
|
filesize: 24
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
size: 24
|
||||||
|
offset: 0x00000138
|
||||||
|
align: 2
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
content: FF4300D1FF0F00B908008052E00308AAFF430091C0035FD6
|
||||||
|
- cmd: LC_SYMTAB
|
||||||
|
cmdsize: 24
|
||||||
|
symoff: 336
|
||||||
|
nsyms: 2
|
||||||
|
stroff: 368
|
||||||
|
strsize: 16
|
||||||
|
LinkEditData:
|
||||||
|
NameList:
|
||||||
|
- n_strx: 7
|
||||||
|
n_type: 0x0E
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
- n_strx: 1
|
||||||
|
n_type: 0x0F
|
||||||
|
n_sect: 1
|
||||||
|
n_desc: 0
|
||||||
|
n_value: 0
|
||||||
|
StringTable:
|
||||||
|
- ''
|
||||||
|
- _arm64
|
||||||
|
- ltmp0
|
||||||
|
- ''
|
||||||
|
- ''
|
||||||
|
- ''
|
||||||
|
...
|
|
@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
|
||||||
BinaryFormat
|
BinaryFormat
|
||||||
Object
|
Object
|
||||||
Support
|
Support
|
||||||
|
TextAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
add_llvm_tool(llvm-libtool-darwin
|
add_llvm_tool(llvm-libtool-darwin
|
||||||
|
|
|
@ -17,4 +17,4 @@
|
||||||
type = Tool
|
type = Tool
|
||||||
name = llvm-libtool-darwin
|
name = llvm-libtool-darwin
|
||||||
parent = Tools
|
parent = Tools
|
||||||
required_libraries = BinaryFormat Object Support
|
required_libraries = BinaryFormat Object Support TextAPI
|
||||||
|
|
|
@ -13,11 +13,13 @@
|
||||||
#include "llvm/BinaryFormat/Magic.h"
|
#include "llvm/BinaryFormat/Magic.h"
|
||||||
#include "llvm/Object/ArchiveWriter.h"
|
#include "llvm/Object/ArchiveWriter.h"
|
||||||
#include "llvm/Object/MachO.h"
|
#include "llvm/Object/MachO.h"
|
||||||
|
#include "llvm/Object/MachOUniversal.h"
|
||||||
#include "llvm/Object/ObjectFile.h"
|
#include "llvm/Object/ObjectFile.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/InitLLVM.h"
|
#include "llvm/Support/InitLLVM.h"
|
||||||
#include "llvm/Support/LineIterator.h"
|
#include "llvm/Support/LineIterator.h"
|
||||||
#include "llvm/Support/WithColor.h"
|
#include "llvm/Support/WithColor.h"
|
||||||
|
#include "llvm/TextAPI/MachO/Architecture.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::object;
|
using namespace llvm::object;
|
||||||
|
@ -33,6 +35,10 @@ static cl::list<std::string> InputFiles(cl::Positional,
|
||||||
cl::ZeroOrMore,
|
cl::ZeroOrMore,
|
||||||
cl::cat(LibtoolCategory));
|
cl::cat(LibtoolCategory));
|
||||||
|
|
||||||
|
static cl::opt<std::string> ArchType(
|
||||||
|
"arch_only", cl::desc("Specify architecture type for output library"),
|
||||||
|
cl::value_desc("arch_type"), cl::ZeroOrMore, cl::cat(LibtoolCategory));
|
||||||
|
|
||||||
enum class Operation { Static };
|
enum class Operation { Static };
|
||||||
|
|
||||||
static cl::opt<Operation> LibraryOperation(
|
static cl::opt<Operation> LibraryOperation(
|
||||||
|
@ -92,7 +98,51 @@ static Error processFileList() {
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error verifyMachOObject(const NewArchiveMember &Member) {
|
static Error validateArchitectureName(StringRef ArchitectureName) {
|
||||||
|
if (!MachOObjectFile::isValidArch(ArchitectureName)) {
|
||||||
|
std::string Buf;
|
||||||
|
raw_string_ostream OS(Buf);
|
||||||
|
for (StringRef Arch : MachOObjectFile::getValidArchs())
|
||||||
|
OS << Arch << " ";
|
||||||
|
|
||||||
|
return createStringError(
|
||||||
|
std::errc::invalid_argument,
|
||||||
|
"invalid architecture '%s': valid architecture names are %s",
|
||||||
|
ArchitectureName.str().c_str(), OS.str().c_str());
|
||||||
|
}
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that a file's architecture [FileCPUType, FileCPUSubtype]
|
||||||
|
// matches the architecture specified under -arch_only flag.
|
||||||
|
static bool acceptFileArch(uint32_t FileCPUType, uint32_t FileCPUSubtype) {
|
||||||
|
uint32_t ArchCPUType, ArchCPUSubtype;
|
||||||
|
std::tie(ArchCPUType, ArchCPUSubtype) = MachO::getCPUTypeFromArchitecture(
|
||||||
|
MachO::getArchitectureFromName(ArchType));
|
||||||
|
|
||||||
|
if (ArchCPUType != FileCPUType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (ArchCPUType) {
|
||||||
|
case MachO::CPU_TYPE_ARM:
|
||||||
|
case MachO::CPU_TYPE_ARM64_32:
|
||||||
|
case MachO::CPU_TYPE_X86_64:
|
||||||
|
return ArchCPUSubtype == FileCPUSubtype;
|
||||||
|
|
||||||
|
case MachO::CPU_TYPE_ARM64:
|
||||||
|
if (ArchCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL)
|
||||||
|
return FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_ALL ||
|
||||||
|
FileCPUSubtype == MachO::CPU_SUBTYPE_ARM64_V8;
|
||||||
|
else
|
||||||
|
return ArchCPUSubtype == FileCPUSubtype;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error verifyAndAddMachOObject(std::vector<NewArchiveMember> &Members,
|
||||||
|
NewArchiveMember Member) {
|
||||||
auto MBRef = Member.Buf->getMemBufferRef();
|
auto MBRef = Member.Buf->getMemBufferRef();
|
||||||
Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr =
|
Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr =
|
||||||
object::ObjectFile::createObjectFile(MBRef);
|
object::ObjectFile::createObjectFile(MBRef);
|
||||||
|
@ -107,6 +157,18 @@ static Error verifyMachOObject(const NewArchiveMember &Member) {
|
||||||
"'%s': format not supported",
|
"'%s': format not supported",
|
||||||
Member.MemberName.data());
|
Member.MemberName.data());
|
||||||
|
|
||||||
|
auto *O = dyn_cast<MachOObjectFile>(ObjOrErr->get());
|
||||||
|
uint32_t FileCPUType, FileCPUSubtype;
|
||||||
|
std::tie(FileCPUType, FileCPUSubtype) = MachO::getCPUTypeFromArchitecture(
|
||||||
|
MachO::getArchitectureFromName(O->getArchTriple().getArchName()));
|
||||||
|
|
||||||
|
// If -arch_only is specified then skip this file if it doesn't match
|
||||||
|
// the architecture specified.
|
||||||
|
if (!ArchType.empty() && !acceptFileArch(FileCPUType, FileCPUSubtype)) {
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
Members.push_back(std::move(Member));
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,18 +179,94 @@ static Error addChildMember(std::vector<NewArchiveMember> &Members,
|
||||||
if (!NMOrErr)
|
if (!NMOrErr)
|
||||||
return NMOrErr.takeError();
|
return NMOrErr.takeError();
|
||||||
|
|
||||||
// Verify that Member is a Mach-O object file.
|
if (Error E = verifyAndAddMachOObject(Members, std::move(*NMOrErr)))
|
||||||
if (Error E = verifyMachOObject(*NMOrErr))
|
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
Members.push_back(std::move(*NMOrErr));
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error processArchive(std::vector<NewArchiveMember> &Members,
|
||||||
|
object::Archive &Lib, StringRef FileName,
|
||||||
|
const Config &C) {
|
||||||
|
Error Err = Error::success();
|
||||||
|
for (const object::Archive::Child &Child : Lib.children(Err))
|
||||||
|
if (Error E = addChildMember(Members, Child, C))
|
||||||
|
return createFileError(FileName, std::move(E));
|
||||||
|
if (Err)
|
||||||
|
return createFileError(FileName, std::move(Err));
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error
|
static Error
|
||||||
addMember(std::vector<NewArchiveMember> &Members, StringRef FileName,
|
addArchiveMembers(std::vector<NewArchiveMember> &Members,
|
||||||
std::vector<std::unique_ptr<MemoryBuffer>> &ArchiveBuffers,
|
std::vector<std::unique_ptr<MemoryBuffer>> &ArchiveBuffers,
|
||||||
const Config &C) {
|
NewArchiveMember NM, StringRef FileName, const Config &C) {
|
||||||
|
Expected<std::unique_ptr<Archive>> LibOrErr =
|
||||||
|
object::Archive::create(NM.Buf->getMemBufferRef());
|
||||||
|
if (!LibOrErr)
|
||||||
|
return createFileError(FileName, LibOrErr.takeError());
|
||||||
|
|
||||||
|
if (Error E = processArchive(Members, **LibOrErr, FileName, C))
|
||||||
|
return E;
|
||||||
|
|
||||||
|
// Update vector ArchiveBuffers with the MemoryBuffers to transfer
|
||||||
|
// ownership.
|
||||||
|
ArchiveBuffers.push_back(std::move(NM.Buf));
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error addUniversalMembers(
|
||||||
|
std::vector<NewArchiveMember> &Members,
|
||||||
|
std::vector<std::unique_ptr<MemoryBuffer>> &UniversalBuffers,
|
||||||
|
NewArchiveMember NM, StringRef FileName, const Config &C) {
|
||||||
|
Expected<std::unique_ptr<MachOUniversalBinary>> BinaryOrErr =
|
||||||
|
MachOUniversalBinary::create(NM.Buf->getMemBufferRef());
|
||||||
|
if (!BinaryOrErr)
|
||||||
|
return createFileError(FileName, BinaryOrErr.takeError());
|
||||||
|
|
||||||
|
auto *UO = BinaryOrErr->get();
|
||||||
|
for (const MachOUniversalBinary::ObjectForArch &O : UO->objects()) {
|
||||||
|
|
||||||
|
Expected<std::unique_ptr<MachOObjectFile>> MachOObjOrErr =
|
||||||
|
O.getAsObjectFile();
|
||||||
|
if (MachOObjOrErr) {
|
||||||
|
NewArchiveMember NewMember =
|
||||||
|
NewArchiveMember(MachOObjOrErr->get()->getMemoryBufferRef());
|
||||||
|
NewMember.MemberName = sys::path::filename(NewMember.MemberName);
|
||||||
|
|
||||||
|
if (Error E = verifyAndAddMachOObject(Members, std::move(NewMember)))
|
||||||
|
return E;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<std::unique_ptr<Archive>> ArchiveOrError = O.getAsArchive();
|
||||||
|
if (ArchiveOrError) {
|
||||||
|
// A universal file member can either be a MachOObjectFile or an Archive.
|
||||||
|
// In case we can successfully cast the member as an Archive, it is safe
|
||||||
|
// to throw away the error generated due to casting the object as a
|
||||||
|
// MachOObjectFile.
|
||||||
|
consumeError(MachOObjOrErr.takeError());
|
||||||
|
|
||||||
|
if (Error E = processArchive(Members, **ArchiveOrError, FileName, C))
|
||||||
|
return E;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error CombinedError =
|
||||||
|
joinErrors(ArchiveOrError.takeError(), MachOObjOrErr.takeError());
|
||||||
|
return createFileError(FileName, std::move(CombinedError));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update vector UniversalBuffers with the MemoryBuffers to transfer
|
||||||
|
// ownership.
|
||||||
|
UniversalBuffers.push_back(std::move(NM.Buf));
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error addMember(std::vector<NewArchiveMember> &Members,
|
||||||
|
std::vector<std::unique_ptr<MemoryBuffer>> &FileBuffers,
|
||||||
|
StringRef FileName, const Config &C) {
|
||||||
Expected<NewArchiveMember> NMOrErr =
|
Expected<NewArchiveMember> NMOrErr =
|
||||||
NewArchiveMember::getFile(FileName, C.Deterministic);
|
NewArchiveMember::getFile(FileName, C.Deterministic);
|
||||||
if (!NMOrErr)
|
if (!NMOrErr)
|
||||||
|
@ -137,43 +275,36 @@ addMember(std::vector<NewArchiveMember> &Members, StringRef FileName,
|
||||||
// For regular archives, use the basename of the object path for the member
|
// For regular archives, use the basename of the object path for the member
|
||||||
// name.
|
// name.
|
||||||
NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
|
NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
|
||||||
|
file_magic Magic = identify_magic(NMOrErr->Buf->getBuffer());
|
||||||
|
|
||||||
// Flatten archives.
|
// Flatten archives.
|
||||||
if (identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
|
if (Magic == file_magic::archive)
|
||||||
Expected<std::unique_ptr<Archive>> LibOrErr =
|
return addArchiveMembers(Members, FileBuffers, std::move(*NMOrErr),
|
||||||
object::Archive::create(NMOrErr->Buf->getMemBufferRef());
|
FileName, C);
|
||||||
if (!LibOrErr)
|
|
||||||
return createFileError(FileName, LibOrErr.takeError());
|
|
||||||
object::Archive &Lib = **LibOrErr;
|
|
||||||
|
|
||||||
Error Err = Error::success();
|
// Flatten universal files.
|
||||||
for (const object::Archive::Child &Child : Lib.children(Err))
|
if (Magic == file_magic::macho_universal_binary)
|
||||||
if (Error E = addChildMember(Members, Child, C))
|
return addUniversalMembers(Members, FileBuffers, std::move(*NMOrErr),
|
||||||
return createFileError(FileName, std::move(E));
|
FileName, C);
|
||||||
if (Err)
|
|
||||||
return createFileError(FileName, std::move(Err));
|
|
||||||
|
|
||||||
// Update vector ArchiveBuffers with the MemoryBuffers to transfer
|
if (Error E = verifyAndAddMachOObject(Members, std::move(*NMOrErr)))
|
||||||
// ownership.
|
|
||||||
ArchiveBuffers.push_back(std::move(NMOrErr->Buf));
|
|
||||||
return Error::success();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that Member is a Mach-O object file.
|
|
||||||
if (Error E = verifyMachOObject(*NMOrErr))
|
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
Members.push_back(std::move(*NMOrErr));
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error createStaticLibrary(const Config &C) {
|
static Error createStaticLibrary(const Config &C) {
|
||||||
std::vector<NewArchiveMember> NewMembers;
|
std::vector<NewArchiveMember> NewMembers;
|
||||||
std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
|
std::vector<std::unique_ptr<MemoryBuffer>> FileBuffers;
|
||||||
for (StringRef Member : InputFiles)
|
for (StringRef FileName : InputFiles)
|
||||||
if (Error E = addMember(NewMembers, Member, ArchiveBuffers, C))
|
if (Error E = addMember(NewMembers, FileBuffers, FileName, C))
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
|
if (NewMembers.empty() && !ArchType.empty())
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no library created (no object files in input "
|
||||||
|
"files matching -arch_only %s)",
|
||||||
|
ArchType.c_str());
|
||||||
|
|
||||||
if (Error E =
|
if (Error E =
|
||||||
writeArchive(OutputFile, NewMembers,
|
writeArchive(OutputFile, NewMembers,
|
||||||
/*WriteSymtab=*/true,
|
/*WriteSymtab=*/true,
|
||||||
|
@ -201,6 +332,10 @@ static Expected<Config> parseCommandLine(int Argc, char **Argv) {
|
||||||
return createStringError(std::errc::invalid_argument,
|
return createStringError(std::errc::invalid_argument,
|
||||||
"no input files specified");
|
"no input files specified");
|
||||||
|
|
||||||
|
if (ArchType.getNumOccurrences())
|
||||||
|
if (Error E = validateArchitectureName(ArchType))
|
||||||
|
return std::move(E);
|
||||||
|
|
||||||
return C;
|
return C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue