Figuring out the target MacOS SDK version in CMake? - macos

I have code that I want to conditionally compile depending on the target SDK version, so that I can use newer features if possible. This can be done by checking the __MAC_OS_X_VERSION_MIN_REQUIRED macro, which tells us the target SDK version, in the source code.
Typically, performing conditional compilation on that macro suffices, and everything is nice and good. However, when targeting a newer SDK version, I would like to use features from a new library (specifically the UniformTypeIdentifiers library) that is not available on an older SDK version. This means that the target_link_libraries() in CMake has to account for this, i.e. link the new library if targeting a newer SDK version, and skip the new library otherwise.
I can't seem to find any way to figure out the target SDK version in CMake. What is the proper way to do this?
Things I have tried:
Checking CMAKE_OSX_DEPLOYMENT_TARGET. This flag is what CMake uses to pass the -mmacosx-version-min flag to clang, that makes it use a particular deployment target. However, it turns out that this may not necessarily be defined. When not defined, clang doesn't get the flag, but since clang is given something like -isysroot /Applications/Xcode-13.3.1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk, the framework sets __MAC_OS_X_VERSION_MIN_REQUIRED to something default (12.3), and so the source code is able to still perform conditional compilation.
Checking if the library exists by using find_library() (e.g. find_library(UNIFORMTYPEIDENTIFIERS_LIBRARY UniformTypeIdentifiers)). This does not work when users want to target a lower version (e.g. by setting CMAKE_OSX_DEPLOYMENT_TARGET), since the new library will still exist.
Essentially, I would like a way for CMake to figure out the deployment target that ultimately gets chosen (i.e. something equivalent to __MAC_OS_X_VERSION_MIN_REQUIRED), so that it can decide whether or not to link with the new library.
How should I do this?
Context:
I'm trying to resolve an issue in my library here.
I also have a testing branch set up to check CMAKE_OSX_DEPLOYMENT_TARGET and the compiler command in the CI builds: GitHub CI builds MacOS 10.15 (without the new library, with CMAKE_OSX_DEPLOYMENT_TARGET) and 11 (with the new library, with CMAKE_OSX_DEPLOYMENT_TARGET), and Circle CI builds MacOS 12 (with the new library, but without CMAKE_OSX_DEPLOYMENT_TARGET).

I couldn't find a way to determine this via some CMake variable, so I rolled by own compilation test for it:
include(CheckCXXSourceCompiles)
check_cxx_source_compiles(
"
#include <Availability.h>
#if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || !defined(__MAC_11_0) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_11_0
static_assert(false);
#endif
int main() { return 0; }
"
NFD_USE_ALLOWEDCONTENTTYPES
)
This ensures full consistency with the check in the source code, at the cost of a slightly longer time to configure the build.

Related

Change c++ standard library on Android in bazel

I'm building a C++11 program that works on osX, but the build for android fails with "error: 'round' is not a member of 'std'".
This is a known problem, associated with the gnustl standard library (https://code.google.com/p/android/issues/detail?id=54418), and the current best workaround seems to be to link against LLVM libc++.
How to do so is documented here for Android Studio or cmake, but I cannot find any documentation for how to do the same with bazel, if it is possible.
A partial answer:
if just building an android static library, the command line call has to specify crosstool_top. This can be set to a specific toolchain using something like --crosstool_top=#androidndk//:toolchain-libcpp.
Options can be found in external/androidndk/BUILD in the directory generated by bazel.
However, if building the library as part of an android application, the crosstool would be inferred. I don't know whether the same approach works, or if not what the answer would be.

Go code building linker error. Can I link manually?

I am building Go code that uses CGo heavily and this code must be compiled into a shared or static library (static is highly preferred). (code for reference)
It all works just fine on Linux and Mac, but on Windows it fails on linker stage either saying that all 4 modes (c-shared, shared, c-archive, archive) are not available or if invoke go tool link -shared manually complains about missing windows specific instructions.
My understanding is that all I need to build usable lib.a is to compile everything I will use into object files (*.o) and then put it through ar to produce usable static library.
Now the question is whether I can completely skip Go's linker and based on prepared .o files create .a manually?
How would I go about doing that if that is even possible?
Looks like gcc on windows is unable to automatically discover necessary shared libraries. The problem was caused by GCC and not by Go.
Although for compiling Go I had to use self-compiled master tip as current release (1.6.2) does not support shared/static libraries on windows/amd64.
Manually feeding gcc with each shared library (ntdll, winmm etc) in default location (C:\Windows\SysWOW64) has fixed the problem.

How does one find what C++11 features have been implemented given a GLIBCXX version

Given a GLIBCXX version of the stdc++ library (example GLIBCXX_3.4.17) given this version, where would one find documentation which specifies what features have been implemented?
Further is there a way to which given the SO NAME version will provide the this same document.
I am working on an embedded system which has an existing version of libstdc++; unfortunately the supplied cross compiler (g++) is at a greater version than what the stdc++ library on the target supports. Upgrading the stdc++ library on the target is not an option. Before I write a lot of code, to only find that it does not run on the target; I would like to know beforehand what is and is not supported.
I have found the GNU Documentation to be useful; however, I am hoping there is a document in which one can get what has been implemented given the symbol version and/or the SO NAME and I just have somehow missed it.
Thanks for any help in advance
given this version, where would one find documentation which specifies what features have been implemented?
You can map a GLIBCXX_A.B.C symbol version to a GCC release by checking
https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
N.B. that won't be precise, because e.g. GCC 5.1 and GCC 5.2 both use GLIBCXX_3.4.21 in the shared library. To tell them apart check the __GLIBCXX__ macro defined by the libstdc++ headers, also documented on that page.
The manuals for libstdc++ releases are at
gcc.gnu.org/onlinedocs/gcc-[X.Y.Z]/libstdc++/manual/
e.g.
https://gcc.gnu.org/onlinedocs/gcc-5.3.0/libstdc++/manual/
Within that manual is a status table showing the implementation status for each standard, the table for C++11 support in GCC 5.3.0 is at
https://gcc.gnu.org/onlinedocs/gcc-5.3.0/libstdc++/manual/manual/status.html#status.iso.2011
Before I write a lot of code, to only find that it does not run on the target; I would like to know beforehand what is and is not supported.
It's not enough to simply avoid using features that aren't supported by the library on the target system. If you link with the cross-compiler then it will depend on the libstdc++.so from that cross-compiler, and will fail to run on the target system if it only has an older libstdc++.so
Upgrading the stdc++ library on the target is not an option.
Then you either need to link statically (creating large executables) or downgrade your cross-compiler to match the target. Or at least force it to use the headers and dynamic library from the same version as found on the target (by overriding the header and library search paths to point to copies of the older files), although that might not work, as the newer g++ might not be able to compile the older headers if they contain some invalid C++ that the older g++ didn't diagnose.

How do I force Xcode to link to a custom version of a system framework?

I have a project that uses OpenAL. The project is built against the 10.5 SDK, and the version of the OpenAL.framework in 10.5 causes some problems. I want to link to a custom-built version of the OpenAL.framework that resides in my source tree.
However, Xcode resolutely refuses to do this. No matter what I try, it insists on linking to the framework located at /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/OpenAL.framework/OpenAL. Here are a couple of things I've tried without success:
Set the path to the framework directory in a variety of ways (relative, absolute) using -F.
Pass the linker the -Z flag to eliminate default link paths, then explicitly pass /System/Library further on in the link process, to ensure that it sees the system paths after my custom library path.
Build my library using a prelinking pass, and explicitly pass the library inside the framework to THAT.
According to man gcc, passing the -F parameter should be sufficient to ensure that a link path is searched before the default paths. Either this isn't happening correctly or I'm misunderstanding the problem, and it seems too simple and obvious to be a linker problem :-)

Cross compile Boost 1.40 for VxWorks 6.4

I'm trying to migrate a project which uses Boost (particularly boost::thread and boost::asio) to VxWorks.
I can't get boost to compile using the vxworks gnu compiler. I figured that this wasn't going to be an issue as I'd seen patches on the boost trac that purport to make this possible, and since the vxworks compiler is part of the gnu tool chain I should be able to follow the directions in the boost docs for cross compilation.
I'm building on windows for a ppc vxworks.
I changed the user-config.jam file as specified in the boost docs, and used the target-os=linux option to bjam, but bjam appears to hang before it can compile. Closer inspection of the commands issued by bjam (by invoking it using the -n option) reveal that it's trying to compile with boost::thread's win32 files. This can't be right, as vxworks uses pthreads.
My bjam command: .\bjam --with-thread toolset=gcc-ppc target-os=linux gcc-ppc is set in user-config to point to the g++ppc vxworks cross compiler.
What am I doing wrong? I believe I have followed the docs to the letter.
If it's #including win32 headers instead of the pthread ones, there could be a discrepancy between the set of macros your compiler is defining and the macros the boost headers are checking for. I had a problem like that with the smart pointer headers, which in an older version of boost would check for __ppc but my compiler defined __ppc__ (or vice versa, can't remember).
touch empty.cpp
ccppc -dD -E empty.cpp
That will show you what macros are predefined by your compiler.
I never tried to compile boost for VxWorks, since I only needed a few of the headers.
Try also adding
threadapi=pthread
The documentation you mention is for Boost.Build -- which is standalone build tool -- and the above flag is something specific to Boost.Thread library. What do you mean by "hang"? Because Boost libraries are huge, it sometimes take a lot of time to scan dependencies prior to build.
If it actually hangs, can you catch bjam in a debugger and produce a backtrace? Also, log of any output will help.

Resources