Preprocessor macros in static library - objective-c

In a Objective-C project I am using a static library, compilation of this static library depends on some preprocessor macros to be set.
When I set these macros in the project depending on the library the library does not see them. But when I set them in the library project it does work.
Since I want to reuse this library for other projects, I require to set the preprocessor macros for each project depending on the library separately. Is there a solution for this?

Preprocessor maros only have any meaning at compile-time, so any library you build will be specific to the values of these preprocessor macros at the time you built the library. You will either need lots of different versions of your library, built with the different possible values of your preprocessor macros, or you could switch to using a different method to control the behaviour of your library code which will work at run-time, e.g. setting some appropriate parameters through the library API.

This is not an answer per se, but something interesting I discovered while struggling with this same issue.
I have a static library (MyLib) that contains a header for logging (Log.h). I have an application project (MyApp) that uses MyLib. Log.h has some resemblance of this:
#ifdef LOG_LEVEL_DEBUG
# define LogDebug(...) NSLog(__VA_ARGS__)
#else
# define LogDebug(...)
#endif
In MyApp build settings, I can use the preprocessor macro LOG_LEVEL_DEBUG to successfully turn off and on logging. This works when I use LogDebug() in source files found in MyApp. However, the MyLib source files that use LogDebug() are not affected by the MyApp build settings. I have to use the MyLib build settings to affect LogDebug() within the MyLib source files.
I am pretty sure I know what is happening but I'd be open to correction. Below is the scenario where MyApp defines LOG_LEVEL_DEBUG in build settings (enabling debugging) and MyLib does not define it (disabling it).
When MyApp builds, it first compiles MyLib where all of the LogDebug() are replaced within the MyLib source files as no-op (since LOG_LEVEL_DEBUG was not defined). After MyLib is compiled, MyApp is compiled and all of the LogDebug() methods within MyApp source are replaced with NSLog() statements because LOG_LEVEL_DEBUG was defined in the build settings.

Related

Export compiler flags for all the targets in modern CMake

I'm porting one project to modern CMake. The project has a compiler flag that must be set and exported for all the targets. To avoid repeating target_compile_option for all the targets I tried with add_compile_options, but the latter seems to not export the flag so that it is not used by downstream targets linking the upstream libraries of my project. So do I really have to call target_compile_option for all my targets or is there a workaround?
Thanks in advance for any help.
Since the libs are always part of the same project you can define a macro in the top-level CMakeLists.txt and use this macro instead of add_library. This way you can add common logic inside the macro in addition to add_library:
macro(my_add_library TARGET_NAME)
add_library(${TARGET_NAME} ${ARGN})
target_compile_options(${TARGET_NAME} PRIVATE -myOption)
endmacro()
...
my_add_library(mylib1 SHARED foo.cpp bar.cpp)
...
my_add_library(mylib2 STATIC util.cpp)
Note that the my_add_library command is also available in subdirectories you add after defining the macro so you should be able to use it for all the libraries.

CMake: static library ignored (objects compiled twice) [duplicate]

I'm trying to move my project to CMake, and at the same time have some optimization on the compilation process.
Here's the deal:
I have several subdirs that are (have to be) each compiled into a static library (this works).
I want to gather all the object files from each subdir into another bigger, complete, static library.
It looks like this:
.
libBig.a # made from object from subdir1 and subdir2
subdir1/
src/
libSubdir1.a
subdir2/
src/
libSubdir2.a
Today, I managed to use a global variable in which every subdir CMakeLists.txt will append its own source files. I use this variable as a "source" input in my big library:
# the big library depends on all the source files
# ${all_src} is automatically filled with each subdir's cpp file
get_property( BigLib_src GLOBAL PROPERTY all_src)
add_library( Big STATIC ${BigLib_src}) # recompiles all the sources
Now, this works, not too bad, but the thing is, all my source files get compiled twice: once for the subdir library, and once for the big library.
CMake seems to forget that it has already built them.
I have to keep the subdir libraries and ar can't merge two static libraries.
Do you know how to do that?
You can use the new OBJECT library feature introduced in CMake 2.8.8. The idea is explained here. Basically, the OBJECT library is a similar concept to the convenience library known from Autotools to group object files.
Check the complete CMake OBJECT library tutorial.
As of CMake 2.8.8, you can do this using the OBJECT library type. See mloksot's answer. The old situation was that each target had its own directory and CMake would build every dependent object for every target. This guards against a case where one source file could be used multiple times with different CFLAGS. (Note that by default CMake is more conservative than automake here: automake will stop reusing object files for different targets only if the targets are built with different CFLAGS (and probably CPPFLAGS, too).

Static library built with CMake as .a with Emscripten instead of .wasm + .js

TL;DR
How do I configure CMake and Emscripten to build my static library to produce a WASM and JS bootstrap file?
I have a static library being built with CMake that I want to build as a WASM library (and JS bootstrap) using Emscripten. Simply using the Emscripten CMake toolchain and adding the appropriate compiler/linker flags result in only a .a file being built - even if -o <project name>.js is added to the compiler and/or linker flags.
The reason is that because I've told CMake I want a static library, it uses CMAKE_AR to build. CMAKE_AR (if undefined) is defined as emar in the Emscripten toolchain file, and emar cannot produce .wasm and .js output.
I have tried creating a new executable target that has a dependency on the library, and otherwise just sets up the compiler/linker settings. However this causes a CMake error, because I've defined an executable target that has no source files (they're associated with the library target). If I add a stub main file, I get an Emscripten warning:
system_libs:WARNING: main() is in the input files, but "_main" is not in EXPORTED_FUNCTIONS, which means it may be eliminated as dead code. Export it if you want main() to run.
I could get round by adding an empty file to exe source file list (probably, I haven't tried), but this feels very much like a hack.
You are correct in that you need to create an executable target in order to produce a .wasm file.
If cmake insists on you creating a dummy source file because it doesn't understand that all the code for your program can come from libraries then I guess you that is your best option.
See CMake: Is it possible to build an executable from only static libraries and no source? for how to work around this limitation of cmake.

CMake: header-only library with generated files

I have a library that needs to carry some constant data injected from the content of non-source files (in this case, OpenGL shader code). To achieve this, I'm using add_custom_command() to generate include files that I can then #include into my code to initialize const static variables.
This works perfectly with regular libraries (static or shared), but now I'd like to make my library header-only. The ability of C++ to let static methods return static data without running the risk of having that data duplicated in each translation unit ("magic statics") makes this possible.
The problem however is that CMake seems to assume that an INTERFACE library (which is the CMake feature that I'm using to create header-only libraries) does not need building - which, in this case, is wrong.
(I realize that there is no actual obligation for my library to be header-only. In this particular case, the reason I want this is that I would like the library, which is doing OpenGL, to remain independent of any specific binding library [such as GLEW or GLee or the newcomer glbinding]. By keeping my library header-only, I can leave that choice to the user - all he needs to do is #include the header of the binding library before mine.)
Does anyone see a way to have CMake trigger the header-generating custom commands, at the latest when the consumer project is being built?
EDIT: I just realized that I could have the "best of both worlds" as it were by keeping my library static but still keeping all my code except for the constant data in the header files. That way, there would still be no need to choose a specific OpenGL binding library.
However, there are still advantages to having a library be header-only - simplicity of use for one - so I'm leaving my question open.
EDIT #2: Here is the relevant part of my CMakeLists.txt file (I only stripped the library dependencies - all header-only - from the end):
set(SHADER_FILES "src/vertex.glsl" "src/fragment.glsl")
add_library(libGPCGUIGLRenderer INTERFACE)
target_sources(libGPCGUIGLRenderer INTERFACE ${SHADER_FILES})
target_include_directories(libGPCGUIGLRenderer BEFORE
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# Embed shader files
source_group("Shader files" FILES ${SHADER_FILES})
set(GENERATED "${CMAKE_CURRENT_BINARY_DIR}/generated")
target_include_directories(libGPCGUIGLRenderer INTERFACE ${GENERATED})
# Find the GPC Bin2C utility
find_package(GPCBin2C REQUIRED)
# Add a custom target and a dependency for each shader file
foreach(shader ${SHADER_FILES})
get_filename_component(name "${shader}" NAME)
set(shader_header "${GENERATED}/${name}.h")
add_custom_command(
OUTPUT ${shader_header}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${shader}
COMMAND GPCBin2C --input=${CMAKE_CURRENT_SOURCE_DIR}/${shader} --output=${shader_header}
)
target_sources(libGPCGUIGLRenderer INTERFACE ${shader_header})
endforeach()
Creating a static library with headers as the only sources worked for me. It is, of course, only a work-around.
Creating a static library with only header files results in an empty library. Mine says !<arch> as the only content.
CMake will automatically get the dependencies correct across sub-directories.
Since all sources are headers, you need to tell CMake which linker language should be used.
Code:
set(OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/generated_include")
add_custom_command(
OUTPUT "${OUTDIR}/outfile.h"
# Replace the next two lines with a proper generating script.
COMMAND mkdir -p ${OUTDIR}
COMMAND touch ${OUTDIR}/outfile.h
)
# Note, I am only adding header files to the library.
add_library(generated-headers STATIC
"${OUTDIR}/outfile.h"
)
set_target_properties(generated-headers
PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(generated-headers PUBLIC ${OUTDIR})
Use in other directories like this:
# In any other directory of the same CMake project:
add_executable(main main.cpp)
target_link_libraries(main generated-headers)
Tested on CMake 3.2, 3.8 and 3.9. Using Ninja and Make generators.
You can use target_sources in CMake 3.1 to tell consumers to compile interface files:
add_library(source_only INTERFACE)
target_sources(source_only INTERFACE foo.cpp)
http://www.cmake.org/cmake/help/v3.1/command/target_sources.html
I ran into comparable problems when trying to use glad: https://github.com/Dav1dde/glad
It uses a custom CMake command to build a binding, which means the files you need to include in the project which uses glad do not exist, so that CMake does not build glad (which would create those files)...
I did not get to try it yet, but example 3 of the following link seems to be a good solution and I believe it may work in your case:
https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/

Xcode 4 : define a preprocessor macro in a dependent target

I have an app named MyApp which is linked to a static library MyLibrary
I've added the MyLibrary project to Xcode and added the MyLibrary target to MyApp's target dependencies.
All this works fine, I can set breakpoints, and I'm pretty happy.
The thing is that I want a conditional log in the library :
#ifdef DEBUG
# define MYDebug(msg, ...) NSLog(#"\nDEBUG -> %# \n(%s:%d)",[NSString stringWithFormat:msg, ## __VA_ARGS__], __PRETTY_FUNCTION__,__LINE__);
#else
# define MYDebug(msg, ...)
#endif
So I have two build configuration for my library :
- Debug has "DEBUG=1" in the target's build settings in "preprocessor macros"
- Prod has nothing
And the MyLibrary target is set to build with the Debug build configuration.
This works fine if I build the static library (.a), and include it in a project.
But if it is built by target dependency, it seems that DEBUG is not defined (MYDebug doesn't log anything).
I've also tried to set DEBUG=1 in MyApp's build settings, but it doesn't work.
Is there something I missed, or another way to do it ?
It should just be "DEBUG" instead of "DEBUG=1". Also, to use a macro that needs an Object assignment (NSString, etc) you need to escape most of the characters like # and " etc..
Here is a screenshot of a working project of mine from xCode 4.1: