[MacPorts] #62426: libc++: using a newer libc++ to build software on older macos systems
MacPorts
noreply at macports.org
Mon Sep 26 03:31:12 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 kencu):
OK, I have an example for you where mixing libc++ versions causes
unexpected issues, I believe. This comes from an example I was looking
over on another package manager.
Take this small {{{test.cxx}}} program, that looks for a nonexistent file
and should generate an error if it is not found:
{{{
#include "llvm/Support/Errc.h"
#include "clang/Basic/FileManager.h"
#include <iostream>
int main() {
clang::FileManager fileMgr((clang::FileSystemOptions()));
auto file = fileMgr.getFileRef("./nonexistant.h", /*OpenFile=*/true);
std::error_code EC = llvm::errorToErrorCode(file.takeError());
std::cout << "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;
}
}}}
compile it like this (I used clang-14 for this, on Monterey):
{{{
clang++-mp-14 -c test.cxx -I/opt/local/libexec/llvm-14/include -std=c++17
-stdlib=libc++ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
-D__STDC_LIMIT_MACROS
}}}
and now link it like this:
{{{
clang++-mp-14 test.o -o test1 -Wl,-rpath,/opt/local/libexec/llvm-14/lib
-L/opt/local/libexec/llvm-14/lib -Wl,-search_paths_first
-Wl,-headerpad_max_install_names -lclangFrontend -lclangSerialization
-lclangDriver -lclangCodeGen -lclangParse -lclangSema -lclangAnalysis
-lclangEdit -lclangASTMatchers -lclangAST -lclangLex -lclangBasic -lLLVM
}}}
check the link, and you will see it is linked against the new
libc++.1.dylib from llvm14:
{{{
% otool -L test1
test1:
@rpath/libLLVM.dylib (compatibility version 1.0.0, current version
14.0.6)
/opt/local/libexec/llvm-14/lib/libc++.1.dylib (compatibility
version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 1311.100.3)
}}}
now run it, and you get this unexpected output:
{{{
% ls *.h
zsh: no matches found: *.h
% ./test1
EC.message is No such file or directory
EC == no_such_file_or_directory is 0
% touch nonexistant.h
cunningh at MacBookPro-2012 ~ % ./test1
EC.message is Undefined error: 0
EC == no_such_file_or_directory is 0
}}}
so you can see that is is not working properly.
Now, let's build it again, this time linking against
/usr/lib/libc++.1.dylib. We'll just manually change it to keep things
simple:
{{{
clang++-mp-14 test.o -o test2 -Wl,-rpath,/opt/local/libexec/llvm-14/lib
-L/opt/local/libexec/llvm-14/lib -Wl,-search_paths_first
-Wl,-headerpad_max_install_names -lclangFrontend -lclangSerialization
-lclangDriver -lclangCodeGen -lclangParse -lclangSema -lclangAnalysis
-lclangEdit -lclangASTMatchers -lclangAST -lclangLex -lclangBasic -lLLVM
install_name_tool -change /opt/local/libexec/llvm-14/lib/libc++.1.dylib
/usr/lib/libc++.1.dylib test2
}}}
and the linkage is as we expect:
{{{
% otool -L test2
test2:
@rpath/libLLVM.dylib (compatibility version 1.0.0, current version
14.0.6)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current
version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 1311.100.3)
}}}
and it works properly:
{{{
% ls *.h
zsh: no matches found: *.h
% ./test2
EC.message is No such file or directory
EC == no_such_file_or_directory is 1
% touch nonexistant.h
% ./test2
EC.message is Undefined error: 0
EC == no_such_file_or_directory is 0
}}}
The reason this happens is because
{{{/opt/local/libexec/llvm-14/lib/libLLVM.dylib}}} is linked against
{{{/usr/lib/libc++.dylib}}}:
{{{
% otool -L /opt/local/libexec/llvm-14/lib/libLLVM.dylib
/opt/local/libexec/llvm-14/lib/libLLVM.dylib:
@rpath/libLLVM.dylib (compatibility version 1.0.0, current version
14.0.6)
/opt/local/lib/libffi.8.dylib (compatibility version 10.0.0,
current version 10.0.0)
/opt/local/lib/libedit.0.dylib (compatibility version 1.0.0,
current version 1.68.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 1311.0.0)
/opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current
version 1.2.12)
/opt/local/lib/libncurses.6.dylib (compatibility version 6.0.0,
current version 6.0.0)
/opt/local/lib/libxml2.2.dylib (compatibility version 12.0.0,
current version 12.14.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current
version 1200.3.0)
}}}
and if {{{test}}} is linked against a different libc++.dylib, then bad
things can happen.
Just to really prove it, let's leave {{{test1}}} linked against the new
libc++, but we'll change
{{{/opt/local/libexec/llvm-14/lib/libLLVM.dylib}}} to link against the new
one too. If this theory is right, test1 should now work properly, and
test2 will be broken:
{{{
sudo install_name_tool -change /usr/lib/libc++.1.dylib
/opt/local/libexec/llvm-14/lib/libc++.1.dylib
/opt/local/libexec/llvm-14/lib/libLLVM.dylib
}}}
{{{
% ls *.h
zsh: no matches found: *.h
% ./test1
EC.message is No such file or directory
EC == no_such_file_or_directory is 1
% ./test2
EC.message is No such file or directory
EC == no_such_file_or_directory is 0
% touch nonexistant.h
% ./test1
EC.message is Undefined error: 0
EC == no_such_file_or_directory is 0
% ./test2
EC.message is Undefined error: 0
EC == no_such_file_or_directory is 0
}}}
so the message here is that when {{{test.cxx}}} is linked against the same
{{{libc++.1.dylib}}} that
{{{/opt/local/libexec/llvm-14/lib/libLLVM.dylib}}} is linked against, all
is well.
If they are linked against different versions of {{{libc++.1.dylib}}} ===>
BOOM. You get garbage.
Now I have to change the linkage in libLLVM.dylib back to how it was
originally, before I forget :>
{{{
% sudo install_name_tool -change
/opt/local/libexec/llvm-14/lib/libc++.1.dylib /usr/lib/libc++.1.dylib
/opt/local/libexec/llvm-14/lib/libLLVM.dylib
}}}
--
Ticket URL: <https://trac.macports.org/ticket/62426#comment:64>
MacPorts <https://www.macports.org/>
Ports system for macOS
More information about the macports-tickets
mailing list