CocoaPods podspec with per architecture flags - cocoapods

QUICK VERSION: I have a library of code that I'm creating a Cocoapods spec file for. It needs different compiler flags based on the architecture. Is that possible?
Explanatory background:
One of the library's files contains some ARM NEON intrinsics code. For armv7 & armv7s the flags are:
s.compiler_flags = '-mfloat-abi=softfp', '-mfpu=neon', '-mcpu=cortex-a9'
The last flag causes a (totally reasonable) compile error on arm64.
Xcode supports per-architecture flags in the Build Settings area, so this has been building fine, until now when a podspec wrapper is required.
Is there a way to configure a CocoaPods spec with per-architecture flags?

One solution, I found via Can you set architecture specific Build Settings in an .xcconfig file in Xcode 4.3?, use xcconfig:
# Common flags
s.compiler_flags = '-mfloat-abi=softfp', '-mfpu=neon'
# Per-arch flags
s.xcconfig = { 'OTHER_CFLAGS[arch=armv7]' => '$(inherited) -mcpu=cortex-a9' ,
'OTHER_CFLAGS[arch=armv7s]' => '$(inherited) -mcpu=cortex-a9'}
Minor CocoaPods bug here, the $(inherited) flag double up the parameters in the Pods.xcconfig:
OTHER_CFLAGS[arch=armv7] = $(inherited) -mcpu=cortex-a9 $(inherited) -mcpu=cortex-a9
OTHER_CFLAGS[arch=armv7s] = $(inherited) -mcpu=cortex-a9 $(inherited) -mcpu=cortex-a9
I wonder if there's a more spec-friendly way to do this via the actual compiler-flags flag?

Related

How to add CFLAGS and CXXFLAGS and LDFLAGS to file.cmake? [duplicate]

I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")

Using -Os/-Oz with Android NDK and cmake for release builds

Using: Andorid Studio 3.1.3, NDKr17b, gradle plugin 3.1.3, gradle-4.5.1-all.zip
I am not able to produce any release build of a shared library using cmake it fails with the following:
arm-linux-androideabi/bin/ld: fatal error: Optimization level must be between 0 and 3
Here is cmake release configuration I use
release {
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=Release",
"-DANDROID_CPP_FEATURES=rtti exceptions",
"-DANDROID_STL=c++_static",
"-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"
cppFlags "-ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -Os"
cFlags "-ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -Os"
}
}
consumerProguardFiles 'proguard-project.txt'
}
I found that ld is called with the following options:
-plugin /home/myhome/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/../lib64/LLVMgold.so -plugin-opt=mcpu=generic -plugin-opt=Os -plugin-opt=-function-sections -plugin-opt=-data-sections
And the problem is existence of "-plugin-opt=Os", when I run the command without this option it links, even that all source is compiled with the proper optimization level.
Using the same configuration with ndk-build works fine (ld call has no such option, it just loads the LLVMgold.so plugin, with no --plugin-opt=Os).
So my question is why this option "-plugin-opt=Os" is applied and how can I remove it? Is this comes from cmake or its from ninja?
I see you're also the filer of this bug, but for anyone else landing here, this is a bug in the Clang LTO plugin: https://github.com/android-ndk/ndk/issues/721.
Even this is a bug in Clang LTO plugin (https://reviews.llvm.org/D30920) - it can be avoided - note that ndk-build system is using the same toolchain, but this problem does not exist.
The solution is to not pass Os option to Clang LTO plugin ("-plugin-opt=Os")
and this can be done by removing -Os option from generic ANDROID_COMPILER_FLAGS_RELEASE, instead pass this option directly to your makefiles, this way it will not be added to Clang LTO plugin. But since ANDROID_COMPILER_FLAGS_RELEASE is not user variable, the only way to do this is to comment two lines (510, 512) in ndk-bundle/build/cmake/android.toolchain.cmake inside Android Sdk folder

Let cmake with clang use c++11 (c++14)

My cmake project shall compile c++14 code. It also uses the CMakeLists.txts included from its external libraries (which are git submodules in my project). The build fails on macOS Sierra (cmake 3.6.2) because the default STL of clang is old and doesn't handle c++11. As far as I understand, there are two STLs shipped with clang: libstdc++ (from gcc) (default) or libc++. So if I add the -stdlib=libc++ option to cmake, the source compiles:
add_compile_options( "$<$<COMPILE_LANGUAGE:CXX>:-std=c++14>" )
add_compile_options( "$<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++>" )
But then it fails at link time because it tries to use libstdc++ for linking. How do I specify in cmake that the new STL libc++ shall be used for the whole build process?
PS: What is the rationale behind clang using the gcc STL by default if it is too old? Could I permanently specify which STL it shall use? Or am I doing something completely wrong (could some of my subprojects silently force gcc?)?
You should rely on CMake to handle compile options. Just specify the wanted standard version:
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
target_compile_features can also be used to require particular features of the standard (and implicitly ask CMake to set the adequate configuration). More information here.
EDIT
You figured out the solution, you also had to remove the following line in the CMakeLists of Ogred3D:
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
Removing it prevented CMake to add the flag mmacosx-version-min=10.7 causing the error.
I suppose, you also need to pass that flang to the linker in the clang case:
link_libraries("-stdlib=libc++")

Xcode "ld: library not found [...] for architecture x86_64"

I want to include libgpg-error and libgcrypt in my swift-project and created the following module.modulemaps:
libgpgerror:
module libgpgerror {
header "/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/gpg-error.h"
link "'/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/libgpgerror-1.21.dylib'"
export *
}
libgcrypt:
module libgcrypt {
header "/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgcrypt/gcrypt.h"
link "'/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgcrypt/libgcrypt-1.6.5.dylib'"
export *
}
I also added the "Swift Compiler - Search Path/Import Paths": /Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/** to both project and target.
The modules are found, the paths are correct.
However if I want to compile the project I get the following error:
ld: library not found for -l'/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/libgpgerror-1.21.dylib' for architecture x86_64
But if I do
file /Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/libgpgerror-1.21.dylib
I get the output
/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/libgpgerror-1.21.dylib: Mach-O 64-bit dynamically linked shared library x86_64
So it seems the library is in the correct place and also has the correct architecture.
Edit
I found a workaround: I removed the link-directive from the modulemaps and linked the libraries manually; this seems to work. But why?
module libgpgerror {
header "/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgpgerror/gpg-error.h"
export *
}
The link directive specifies only the name of the linked library. That is it should specify the suffix of the linker flag for the library. It appears that the directive take "-l" and concatenates the name to produce the linker flag.
This means that the correct way to specify your module map is as follows.
module CGcrypt {
header "/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgcrypt/gcrypt.h"
link "gcrypt"
export *
}
This will generate the linker flag -lgcrypt which is the correct linker flag.
However, there is another problem which is that the linker needs to be able to find the dylib file for gcrypt and by default it only looks on certain paths. Those paths can be found by running clang -Xlinker -v. The output for me looks like this:
tylercloutier$ clang -Xlinker -v
#(#)PROGRAM:ld PROJECT:ld64-264.3.101
configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em (tvOS)
Library search paths:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib
... more stuff ...
Now I'm not sure, but I suspect that the normal search paths are probably
/usr/lib
/usr/local/lib
but I think that Xcode has altered my search paths to point the the MacOSX10.11.sdk/usr/lib, which, incidentally, has basically the same set of files as /usr/lib (they are not symlinked). Indeed, in El Capitan, because of System Integrity Protection even sudo will not allow you to edit /usr/lib.
Thus the problem that I am having is that even though I've installed my libraries to /usr/local/lib, clang is not able to link them. In order to fix that I can specify the search path explicitly.
swift build -Xlinker -L/usr/local/lib/
And we're off to the races. I can even generate an xcodeproj which will have the appropriate linker flag already set in Other Linker Flags.
swift build -Xlinker -L/usr/local/lib/ --generate-xcodeproj
If you leave out the link directive in the module map file, you can specify it as a flag:
module CGcrypt {
header "/Volumes/Xcode/Programme/Swifts/KCAnon/KCAnon_Client/Libs/libgcrypt/gcrypt.h"
export *
}
Like so
swift build -Xlinker -L/usr/local/lib/ -lgcrypt
How to change the default library search paths, I don't know. But it would be great if someone else could shed light on this matter!

Xcode: Build Settings - Other Linker Flags: What is -licucore?

-licucore was already in Other Linker Flags for a target that I added to my project. Isn't it normally blank?
libicucore is the Mac OS X regexp library. Don't know why it's already included in your project perhaps your settings have been modified from the defaults.

Resources