Build Objective-C Library with CMake with ARC enabled - objective-c

I am trying to build an Objective-C ARC enabled library using CMake. When using the "Unix Makefiles" generator I run into a warning:
method possibly missing a [super dealloc] call
I don't run into this warning when using the XCode generator. Is there a flag I can pass to CMake to make sure that the command line build also recognizes this to be an ARC build and not have that warning generated?
Thanks

You need to let CMake know that you want to build the project with ARC. Otherwise, it will show the warning.
Option 1
However, CTSetObjCArcEnabled is only available only if we have cmake-toolkit installed. If it is not installed, you can use the following:
set_property (TARGET target_name APPEND_STRING PROPERTY
COMPILE_FLAGS "-fobjc-arc")
Option 2 (deprecated since 3.0)
Use CTSetObjCARCEnabled. Reference is available here:
Enables or disables Objective-C Automatic Reference Counting on a per-directory, per-target or per-source basis.
CTSetObjCARCEnabled(<value>
<DIRECTORY | TARGETS targets... | SOURCES sources... >)
Useful Tip
Also, as recommended from this answer, it is helpful to use the following to make sure the project is compiled with ARC enabled:
#if ! __has_feature(objc_arc)
#error "ARC is off"
#endif

An alternative approach is to specify per-target compiler flags. This could be considered more inline with modern CMake:
target_compile_options(target_name PUBLIC "-fobjc-arc")
Note: using PUBLIC will transitively forward this compiler flag to other targets depending on this one. Replacing by PRIVATE will prevent this propagation.

XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC works for me. See https://github.com/forexample/testapp/blob/master/CMakeLists.txt
set_target_properties(
${APP_NAME}
PROPERTIES
MACOSX_BUNDLE YES
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
)

Another option if you want all Objective-C(++) files to be built with ARC:
set(CMAKE_OBJC_FLAGS "-fobjc-arc")
set(CMAKE_OBJCXX_FLAGS "-fobjc-arc")

Related

How would I include asio library using CMake?

I am trying to work on a project for a class and I want to use CMake to build the project. My current project looks like
|-bin
|-CMakeLists.txt
|-include
|-asio-1.12.2
|-chat_message.hpp
|-chat_message.cpp
|-CMakeLists.txt
|-src
|-Server.cpp
although my Server.cpp needs asio.hpp that is in /include/asio-1.12.2/include.
The professor has a makefile that compiles it with the flags
-DASIO_STANDALONE -Wall -O0 -g -std=c++11 -I./include -I./include/asio-1.12.2/include. My CMakeLists files look like this:
./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
PROJECT(Server VERSION 0.0.1)
SET(CPP_STANDARD 11)
SET(CPP_STANDARD_REQUIRED True)
ADD_SUBDIRECTORY(include)
ADD_EXECUTABLE(Server src/Server.cpp)
TARGET_LINK_LIBRARIES(
Server PRIVATE
chat_message
asio
)
./include/CMakeLists.txt
ADD_LIBRARY(
chat_message
chat_message.cpp
chat_message.hpp
)
ADD_LIBRARY(
asio
asio-1.12.2/include/asio.cpp
asio-1.12.2/include/asio.hpp
)
TARGET_INCLUDE_DIRECTORIES(
chat_message PUBLIC "${CMAKE_SOURCE_DIR}/include"
asio PUBLIC "${CMAKE_SOURCE_DIR}/include/asio-1.12.2/include"
)
How would I link the asio header file to the Server.cpp file WITH the flags needed?
First of all, as Tzyvarev pointed out in the comments, you must split the target_include_directories() command into two separate commands. This will then propagate asio and chat_message's include directories to your Server target, which will turn add the correct include flags to the compiler flags.
Note: I'd recommend switching from CMAKE_SOURCE_DIR to CMAKE_CURRENT_SOURCE_DIR and altering your paths accordingly to make your life slightly easier if in future you decide to change your project structure, as you will usually keep a CMakeLists.txt file in the same directory as the sources for a target it creates.
The -DASIO_STANDALONE option can be added with a target_compile_definitions() call:
target_compile_definitions(asio PUBLIC ASIO_STANDALONE)
Note you do not need the -D - CMake will generate the correct compiler flag for you. Also, since this is a requirement for the asio target and all its consumers will need it, it should be added to that, rather than its consumers - it will then propagate to dependencies as needed.
In your CMakeLists.txt you have set the CPP_STANDARD and CPP_STANDARD_REQUIRED variables. The one's you're after are CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED respectively.
This will set the flag for all targets throughout your project.
There are different ways to add the error, optimization and debug symbols flags and which one you use depends on your use case. The following is not an exhaustive list.
If you want everyone who builds the library to have these, irrespectively of build configuration (debug/release/etc), you set the CMAKE_CXX_FLAGS variable in your CMakeLists.txt
If you want everyone to have the flags, but only in certain build types, set the CMAKE_CXX_FLAGS_<CONFIG> variable, where <CONFIG> is the build type selected (DEBUG/RELEASE/MINSIZEREL/RELWITHDEBINFO are available by default)
If you don't want to force the flags upon everyone, before invoking CMake you can set the CXXFLAGS environment variable. But note that according to documentation this will be ineffective if CMAKE_CXX_FLAGS is set in your CMake scripts.
If you want to add flags to a single target, you can call target_compile_options on it, and set the appropriate visibility option to enable/disable propagation to consumers.
However in general you do need to think about portability when using these. For example GCC may support a certain flag which in Clang could be different.
Edit to address this comment
Since the header-only ASIO library does not like being compiled with the compiler definition mentioned above, there are two ways to address it:
Remove the ASIO_STANDALONE compiler flag
This will be the easiest thing to do from your point of view, but as a knock-on effect it will require you to have Boost installed on your system, as not having the flag above will cause the pre-processor to go through some Boost includes. There may be other effects, but this is the first one I encountered before moving on to the solution below.
Keep the flag, and use a CMake interface library
add_library() can allow you to add a target that does not actually produce any compiled objects/libraries/executables, but simply a logical CMake target that can posses properties just like any other ones - include directories, link libraries, etc. So as a minimum you could do this:
add_library(asio INTERFACE)
target_compile_options(asio INTERFACE ASIO_STANDALONE)
target_include_directories(asio INTERFACE <dir where asio.hpp lives>)
target_link_libraries(asio INTERFACE <threads>) # Using ASIO requires you link your final executable/library with your system's threading library (e.g. pthread on linux)
Then when you link another target with it like
target_link_libraries(any_lib PRIVATE asio)
any_lib will inherit all properties required to build with ASIO.
The solution you choose will be dictated by your use case, but if you have to do it the same way as your professor, then go the INTERFACE library route.

CMake idiom for overcoming libstdc++ filesystem weirdness?

If you build C++14 code with G++ and libstdc++, there's a library named libstdc++fs, which is separate from the rest of libstdc++, and contains the code for std::experimental::filesystem. If you don't link against it, you'll get undefined references.
The "trick" I'm using for overcoming this right now is:
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CXX_FILESYSTEM_LIBRARIES "stdc++fs")
endif()
and later:
target_link_libraries(my_target PUBLIC ${CXX_FILESYSTEM_LIBRARIES})
but - I don't like having to place this code in every project I work on. Is there a simpler or more standard idiom I could use? Some way this will all happen implicitly perhaps, with some CMake behind-the-scences magic?
tl;dr: Nothing right now, wait for a newer CMake version
As #Pedro graciously points out, this is a known problem, and there is an open issue about it at KitWare's GitLab site for CMake:
Portable linking for C++17 std::filesystem
If using CMAKE_CXX_STANDARD=17 and std::filesystem, GCC requires linking of an extra library: stdc++fs. ... If C++17 is enabled, would it be worth automatically linking to stdc++fs for GCC versions which require this? Likewise for any quirks in other compilers or libraries.
The KitWare issue is about C++17, for which apparently you still need the separate extra library (i.e. it's not just because of the "experimentality" in C++14). Hopefully we'll see some traction on this matter - but
Note: If you're experiencing this problem with C++17's std::filesystem, you're in luck - that code is built into libstdc++ beginning with GCC 9, so if you're using g++ 9 or later, and std::filesystem, you should no longer experience this problem.

clang-tidy cmake exclude file from check

I have a dependency as source in my project that I have no control over.
I'm using cmake's clang-tidy integration to analyze my code, and this dependency is firing A LOT of warnings. Is there a way to tell cmake not to run clang-tidy on specific files ?
I tried to add the files to the -line-filter option of clang-tidy, but this doesn't work:
set_target_properties(target PROPERTIES
CXX_CLANG_TIDY "${clang_tidy_loc};\
${TIDY_CONFIG} \
-line-filter=\"[\
{\"name\":\"path/to/file.cpp\"},\
{\"name\":\"path/to/file.h\"}\
]\"")
If the solution could work with other static analyzers like cppcheck it would be really nice.
Thanks.
If some property - like CXX_CLANG_TIDY - is only available on target level, you have to move the files you want to have different settings for into a separate new target itself.
This can be done by using OBJECT libraries.
In your case something like:
add_library(
target_no_static_code_analysis
OBJECT
path/to/file.cpp
path/to/file.h
)
# NOTE: Resetting only needed if you have a global CMAKE_CXX_CLANG_TIDY
set_target_properties(
target_no_static_code_analysis
PROPERTIES
CXX_CLANG_TIDY ""
)
...
add_library(target ${other_srcs} $<TARGET_OBJECTS:target_no_static_code_analysis>)
References
CMake/Tutorials/Object Library
In case you have a header only library I use SYSTEM (should also be possible for OBJECT libraries)
add_library(
header_only_library_no_static_code_analysis
INTERFACE
)
target_include_directories(
header_only_library_no_static_code_analysis
SYSTEM # Adds -isystem instead of -I and this tells clang-tidy not to analyze these includes
INTERFACE
path/to
)
I couldn't use this approach for a long time due to following bug
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1698539
But with GNU Arm Embedded Toolchain Version 9-2020-q2-update it seems resolved :)

Using build type in CMake 3.x

In the 2.x version of CMake, the cmake option CMAKE_BUILD_TYPE controlled options to be passed to the compiler. For example, if CMAKE_BUILD_TYPE=RelWithDebInfo then the options passed to the compiler was CMAKE_CXX_FLAGS_RELWITHDEBINFO for C++ and CMAKE_C_FLAGS_RELWITHDEBINFO for C (http://binglongx.wordpress.com/tag/cmake_build_type/).
In the new 3.x version of CMake there are commands add_compile_options and target_compiler_options for adding options to the compiler (What is the modern method for setting general compile flags in CMake?).
Questions
How do I define which build type CMake should use? Is it still, for example, cmake -DCMAKE_BUILD_TYPE=Debug?
How do I make use of this build type in my CMakeLists.txt?
Has CMake defined all the build types, or can I define custom, additional, build types?
Has CMake set any default compiler options for each of the build types (for example -g for the Debug build type)?
Please try to stick to a single question per question in the future. You might risk getting closed as too broad otherwise. Also, you are more likely to get good answers for well-defined, precise questions.
How do I define which build type CMake should use? Is it still, for
example, cmake -DCMAKE_BUILD_TYPE=Debug?
Yes, this did not change.
How do I make use of this build type in my CMakeLists.txt?
Use generator expressions. For example:
target_compile_options(my_program PUBLIC $<$<CONFIG:Debug>:-Werror>)
# Warnings are errors for debug build only
Has CMake defined all the build types, or can I define custom,
additional, build types?
You can add your own type if the defaults don't cut it for you. Note though that this can be a bit fiddly, so I wouldn't do it unless you have good reasons. Take a look at CMAKE_CONFIGURATION_TYPES.
Has CMake set any default compiler options for each of the build types
(for example -g for the Debug build type)?
CMake does a pretty good job at choosing the right defaults for the different configurations. In particular, Debug and RelWithDebInfo builds generate symbols correctly (-g on gcc) and Release builds are optimized quite well.

Compile openCV with CMake: set architecture and optimization flags

I need to compile OpenCV for i486 architecture. I would like to set optimization flags to O3. The problem is that can't find a way to set compiler flags in cmake file or with configuration script.
CMake allows you to set your compiler flags on a configuration basis. By default, if you choose the Release configuration, the optimization flags will probably be enabled. If you want to turn them on yourself, use:
set(CMAKE_C_FLAGS_RELEASE "-O3")
and choose the Release configuration (you could also do this using the Cache or the GUI):
set(CMAKE_BUILD_TYPE Release)
Relevant doc:
CMAKE_C_FLAGS_RELEASE
CMAKE_BUILD_TYPE
NB: replace C by CXX if you use C++
I believe you can either set the CFLAGS or CXXFLAGS as environment variables before you run cmake. Alternatively, have a look at using the CMAKE_C_FLAGS inside the relevant CMakeLists.txt files.
Hope that helps!
./opencv/cmake/OpenCVCompilerOptions.cmake
Line 29:
set(OPENCV_EXTRA_FLAGS_RELEASE "-O3")
Note the overrides at the top though.