libarchive / libarchive

Multi-format archive and compression library

Home Page:http://www.libarchive.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to build a universal (x86-64 and ARM64) library for macOS

dixlorenz opened this issue · comments

On my M1 (current OS, current Xcode) I tried

./configure CC="gcc -arch x86_64 -arch arm64"

and the result looked good, at least the library was about twice as big and my program using libarchive.a did run. But the same command on an Intel Mac (same OS, same compiler, practically the same setup) stopped with an error:

checking for libxml-2.0... yes
checking for xmlInitParser in -lxml2... no
configure: error: in `/Users/dlorenz/Downloads/libarchive-3.7.4':
configure: error: Missing xml2 library

Just using ./configure worked fine on that machine, but obviously does not create a universal library.

I tried installing from macports, but that won't result in a universal binary.

I tried simply coping the universal library and the 2 headers over to the intel Machine, but when trying to compile my program with it, I got the "Undefined symbols for architecture x86_64" errors below.

Undefined symbols for architecture x86_64:
"_BZ2_bzDecompress", referenced from:
_bzip2_filter_read in libarchive.a[x86_64]40
_extract_pack_stream in libarchive.a[x86_64]54
_rd_contents in libarchive.a[x86_64]69
_archive_read_format_zip_read_data in libarchive.a[x86_64]70
"_BZ2_bzDecompressEnd", referenced from:
_bzip2_filter_read in libarchive.a[x86_64]40
_bzip2_filter_close in libarchive.a[x86_64]40
_archive_read_format_7zip_cleanup in libarchive.a[x86_64]54
_extract_pack_stream in libarchive.a[x86_64]54
_init_decompression in libarchive.a[x86_64]54
_xar_cleanup in libarchive.a[x86_64]69
_rd_contents_init in libarchive.a[x86_64]69
...
"_BZ2_bzDecompressInit", referenced from:
_bzip2_filter_read in libarchive.a[x86_64]40
_bzip2_filter_read in libarchive.a[x86_64]40
_init_decompression in libarchive.a[x86_64]54
_init_decompression in libarchive.a[x86_64]54
_rd_contents_init in libarchive.a[x86_64]69
_rd_contents_init in libarchive.a[x86_64]69
_archive_read_format_zip_read_data in libarchive.a[x86_64]70
...
"_crc32", referenced from:
_gzip_filter_read in libarchive.a[x86_64]44
_archive_read_format_7zip_bid in libarchive.a[x86_64]54
_archive_read_format_7zip_read_header in libarchive.a[x86_64]54
_archive_read_format_7zip_read_header in libarchive.a[x86_64]54
_archive_read_format_7zip_read_header in libarchive.a[x86_64]54
_archive_read_format_7zip_read_data in libarchive.a[x86_64]54
_header_bytes in libarchive.a[x86_64]54
...
"_iconv", referenced from:
_iconv_strncat_in_locale in libarchive.a[x86_64]71
"_iconv_close", referenced from:
_free_sconv_object in libarchive.a[x86_64]71
_free_sconv_object in libarchive.a[x86_64]71
"_iconv_open", referenced from:
_get_sconv_object in libarchive.a[x86_64]71
"_inflate", referenced from:
_gzip_filter_read in libarchive.a[x86_64]44
_extract_pack_stream in libarchive.a[x86_64]54
_cab_read_ahead_cfdata in libarchive.a[x86_64]58
_archive_read_format_iso9660_read_data in libarchive.a[x86_64]61
_rd_contents in libarchive.a[x86_64]69
_archive_read_format_zip_seekable_read_header in libarchive.a[x86_64]70
_zip_read_data_deflate in libarchive.a[x86_64]70
...
"_inflateEnd", referenced from:
_gzip_filter_read in libarchive.a[x86_64]44
_gzip_filter_close in libarchive.a[x86_64]44
_archive_read_format_7zip_cleanup in libarchive.a[x86_64]54
_archive_read_format_cab_cleanup in libarchive.a[x86_64]58
_archive_read_format_iso9660_cleanup in libarchive.a[x86_64]61
_xar_cleanup in libarchive.a[x86_64]69
_archive_read_format_zip_cleanup in libarchive.a[x86_64]70
...
"inflateInit2", referenced from:
_gzip_filter_read in libarchive.a[x86_64]44
_init_decompression in libarchive.a[x86_64]54
_cab_read_ahead_cfdata in libarchive.a[x86_64]58
_archive_read_format_zip_seekable_read_header in libarchive.a[x86_64]70
_zip_read_data_deflate in libarchive.a[x86_64]70
"inflateInit", referenced from:
_archive_read_format_iso9660_read_data in libarchive.a[x86_64]61
_xar_read_header in libarchive.a[x86_64]69
_rd_contents_init in libarchive.a[x86_64]69
"_inflateReset", referenced from:
_init_decompression in libarchive.a[x86_64]54
_cab_read_ahead_cfdata in libarchive.a[x86_64]58
_cab_read_ahead_cfdata in libarchive.a[x86_64]58
_archive_read_format_iso9660_read_data in libarchive.a[x86_64]61
_xar_read_header in libarchive.a[x86_64]69
_rd_contents_init in libarchive.a[x86_64]69
_archive_read_format_zip_seekable_read_header in libarchive.a[x86_64]70
...
"_inflateSetDictionary", referenced from:
_cab_read_ahead_cfdata in libarchive.a[x86_64]58
"_xmlCleanupParser", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlFreeTextReader", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlReaderForIO", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderConstLocalName", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderConstValue", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderIsEmptyElement", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderMoveToFirstAttribute", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderMoveToNextAttribute", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderNodeType", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderRead", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69
_xml2_read_toc in libarchive.a[x86_64]69
"_xmlTextReaderSetErrorHandler", referenced from:
_xml2_read_toc in libarchive.a[x86_64]69

This is quite a complicated thing to do - libarchive has several optional dependencies, some of which are provided by macOS and some of which aren't.

If you look at the output of ./configure --help you'll see zlib, bz2lib, libb2, iconv, lz4, zstd, lzma, xml2, expat, etc. The configure script will try and find the ones that are available, but that situation can be "polluted" if you have Homebrew (or similar) installed and providing headers/libraries for things.

Personally, I solved all of this by adding libb2, liblzma, liblz4, libzstd and libarchive as git submodules in my project, then wrote a script to compile each of those to static libraries, using clang and the macOS SDK, for arm and x86_64 individually, then used lipo to combine each of the architecture-specific libraries into universal libraries, then told Xcode to link against them, with my vendor/lib directory as the first library search path. I also built separate Debug/Release versions so I can step into libarchive/deps in Xcode's debugger.

I'd be happy to share the script I used, but it is very much tied to how I set up the git submodules and path structure within my project. If you were to run this without that same structure, you would definitely cause big problems for yourself.

Linker search path:
Screenshot 2024-05-31 at 10 56 23

Linker flags:
Screenshot 2024-05-31 at 10 51 07

that sound very complicated indeed. For the moment I resigned to just using libarchive.tbd from macOS, "borrowing" the headers from somewhere else. It might not be an officially sanctioned way and as far as I understood it wouldn't be possible for an App for the Appstore, but I don't need that and it works for me.