[MacPorts] #62426: libc++: using a newer libc++ to build software on older macos systems

MacPorts noreply at macports.org
Tue Sep 27 12:52:33 UTC 2022


#62426: libc++: using a newer libc++ to build software on older macos systems
-------------------------------------+--------------------
  Reporter:  kencu                   |      Owner:  kencu
      Type:  enhancement             |     Status:  closed
  Priority:  Normal                  |  Milestone:
 Component:  ports                   |    Version:
Resolution:  fixed                   |   Keywords:
      Port:  libcxx macports-libcxx  |
-------------------------------------+--------------------

Comment (by RJVB):

 Replying to [comment:67 kencu]:
 > It's not a clean mapping. At last count, Apple was carrying something
 like 12,000 patches for xcode on top of the LLVM tree, or some similar
 number. So their versions are not quite llvm's versions.

 This could explain things, if they introduce change that cause ABI
 compatibility problems. But if they do that it's a miracle that we never
 ran into issues using the libc++ headers from clang++-mp-XY with
 /usr/lib/libc++.dylib! I suppose you can see why?!

 Even if the mapping isn't clean we can still make it based on the LLVM
 version Apple apply their patches to. For instance, suppose OS Foo
 includes libc++ 1200.0.1 which is a patched version of LLVM 12.0.1 that
 mapping could say 1200.0.1 corresponds to stock 12.0.2 (which AFAIK would
 never exist). Then `port:libcxx_macports` could set the current_version of
 libc++ 13.0.x to `1200.13.x`, or something comparable that sits between 2
 Apple libc++ version numbers.


 ----


 I've been tinkering with your example.

 libcxx-test.cpp:
 {{{
 #include "llvm/Support/Errc.h"
 #include "clang/Basic/FileManager.h"

 #include <iostream>

 int main(int argc, const char *argv[])
 {
   clang::FileManager fileMgr((clang::FileSystemOptions()));

   for (int i = 0 ; i < argc ; ++i) {
 #if LLVM_VERSION_MAJOR > 9
     auto file = fileMgr.getFileRef(argv[i], /*OpenFile=*/true);
     std::error_code EC = llvm::errorToErrorCode(file.takeError());
 #else
     auto file = fileMgr.getFile(argv[i], /*OpenFile=*/true);
     std::error_code EC = file ?
 llvm::errorToErrorCode(llvm::Error::success()) :
 llvm::errorToErrorCode(llvm::createStringError(llvm::errc::no_such_file_or_directory,
 "%s"));
 #endif

     std::cout << argv[i] << " : EC.message is " << EC.message() << "\n";

     bool not_no_such = (EC != llvm::errc::no_such_file_or_directory);
     bool is_no_such = !not_no_such;

     std::cout << "EC == no_such_file_or_directory is " << is_no_such <<
 "\n";
   }

   return 0;
 }
 }}}

 build-libcxx-test.sh:
 {{{
 #!/bin/sh

 CC="$1"
 shift

 # -I/opt/local/libexec/llvm-14/include
 -Wl,-rpath,/opt/local/libexec/llvm-14/lib -L/opt/local/libexec/llvm-14/lib

 ${CC} -c libcxx-test.cpp -std=c++17 -stdlib=libc++
 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS \
      -D__STDC_LIMIT_MACROS "$@"
 ${CC} libcxx-test.o -o libcxx-test -Wl,-search_paths_first
 -Wl,-headerpad_max_install_names -lclangFrontend \
      -lclangSerialization -lclangDriver -lclangCodeGen -lclangParse
 -lclangSema -lclangAnalysis -lclangEdit \
      -lclangASTMatchers -lclangAST -lclangLex -lclangBasic -lLLVM "$@"
 }}}

 With port:clang-12 I can reproduce your symptom, and if I link explictly
 to /usr/lib/libc++.dylib I get correct behaviour

 {{{
 > build-libcxx-test.sh clang++-mp-12 -I/opt/local/libexec/llvm-12/include/
 -Wl,-rpath,/opt/local/libexec/llvm-12/lib -L/opt/local/libexec/llvm-12/lib
 -Wl,-rpath,/opt/local/lib -L/opt/local/lib /usr/lib/libc++.dylib &&
 libcxx-test ./nonexistant.h libcxx-test.cpp
 clang: warning: -Wl,-rpath,/opt/local/libexec/llvm-12/lib: 'linker' input
 unused [-Wunused-command-line-argument]
 clang: warning: -Wl,-rpath,/opt/local/lib: 'linker' input unused
 [-Wunused-command-line-argument]
 clang: warning: /usr/lib/libc++.dylib: 'linker' input unused [-Wunused-
 command-line-argument]
 clang: warning: argument unused during compilation:
 '-L/opt/local/libexec/llvm-12/lib' [-Wunused-command-line-argument]
 clang: warning: argument unused during compilation: '-L/opt/local/lib'
 [-Wunused-command-line-argument]
 libcxx-test : EC.message is Undefined error: 0
 EC == no_such_file_or_directory is 0
 ./nonexistant.h : EC.message is No such file or directory
 EC == no_such_file_or_directory is 1
 libcxx-test.cpp : EC.message is Undefined error: 0
 EC == no_such_file_or_directory is 0
 }}}

 This also applies to using `/opt/local/lib/libc++.dylib` from my own
 `macstrop:libcxx` port
 {{{
 > build-libcxx-test.sh clang++-mp-12 -I/opt/local/libexec/llvm-12/include/
 -Wl,-rpath,/opt/local/libexec/llvm-12/lib -L/opt/local/libexec/llvm-12/lib
 -Wl,-rpath,/opt/local/lib -L/opt/local/lib /opt/local/lib/libc++.dylib &&
 libcxx-test ./nonexistant.h libcxx-test.cpp && ldd libcxx-test
 clang: warning: -Wl,-rpath,/opt/local/libexec/llvm-12/lib: 'linker' input
 unused [-Wunused-command-line-argument]
 clang: warning: -Wl,-rpath,/opt/local/lib: 'linker' input unused
 [-Wunused-command-line-argument]
 clang: warning: /opt/local/lib/libc++.dylib: 'linker' input unused
 [-Wunused-command-line-argument]
 clang: warning: argument unused during compilation:
 '-L/opt/local/libexec/llvm-12/lib' [-Wunused-command-line-argument]
 clang: warning: argument unused during compilation: '-L/opt/local/lib'
 [-Wunused-command-line-argument]
 libcxx-test : EC.message is Undefined error: 0
 EC == no_such_file_or_directory is 0
 ./nonexistant.h : EC.message is No such file or directory
 EC == no_such_file_or_directory is 0
 libcxx-test.cpp : EC.message is Undefined error: 0
 EC == no_such_file_or_directory is 0
 libcxx-test:
         /opt/local/libexec/llvm-12/lib/libLLVM.dylib (compatibility
 version 1.0.0, current version 12.0.1)
         /opt/local/lib/libc++.1.dylib (compatibility version 1.0.0,
 current version 9.0.1)
         /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
 version 1197.1.1)
 }}}

 I would have to build my `macstrop:libcxx at 12.0.1` to verify if something
 changed between libc++ 9 and libc++ 12 . That is not impossible of course,
 but then again *AFAIK* libc++ 9 is new enough to provide support for
 current C++ standards, on systems that ship an earlier version.

 Now, the weird thing I see is when I remove
 `/opt/local/libexec/llvm-12/lib/libc++.dylib` so the linker/editor doesn't
 find that libc++ any more.

 In that case, `ld` refuses to acknowledge both libc++.dylib versions that
 are in its path. I can add either explicitly (= with the absolute path) as
 in the commands shown above but without that I get missing symbol errors
 for everything provided by libc++ .
 Can you confirm this? I have no explanation for it, but it would be
 interesting to rebuild clang-12 WITHOUT libc++ .

 I can do that, but it takes hours on my system so if that is not the case
 for you I'd appreciate if you could check first if that makes a
 difference.

-- 
Ticket URL: <https://trac.macports.org/ticket/62426#comment:68>
MacPorts <https://www.macports.org/>
Ports system for macOS


More information about the macports-tickets mailing list