I am trying to prepare CMakeLists.txt for closed properietary toolchain and curretly I am stuck in some problems. Build environment is linux so created Makefile have unix makefile style (e.g. library pre/suffixes).
Compiler and linker unfortunatelly have nonstandard syntax and some conventions is in unix some windows and some custom style.
I partially solved this problem by re-defining variable:
CMAKE_C_LINK_EXECUTABLE and CMAKE_C_COMPILE_OBJECT
One of problem is linker expect to provide standard library name like: libc.lib libm.lib etc.
but when I use: target_link_libraries(my_target_name PRIVATE libc.lib libm.lib) finally created makefile caused call compiler with parameter -llibc.lib and it cause error.
I tried manipulate suffixes and prefixes by setting: CMAKE_STATIC_LIBRARY_SUFFIX and CMAKE_STATIC_LIBRARY_PREFIX but I see no influence.
I've also tried to use call cmake with such define: -DCMAKE_TOOLCHAIN_FILE=../cmake/mytoolchain.cmake but as side effect I observed that some intrnal variables was reset to defaults (e.g. object file extension change from source.c.o to source.c.obj in case of c sources) and it's not acceptable for platform linker and cause linking error.
From my perspective looks like I have to create new custom configuration for platform I use but I have no idea how to start. I see that MSVC have different configuration than unix makefiles but which files determine it's behavior?
Related
I have a package, libtorch, that depends on libraries that use the keyword slots for some function (e.g. in Aten). In the meantime, the project that I am using is based on Qt, which use slots as a special keyword (macro), which then interferes with torchlib.
The solution to avoid such interference is to add the QT_NO_KEYWORDS definition when importing the external library that enters in conflict with Qt: Turning the no_keyword (Qt option) ON in a cmake file to work with boost::signals
It has then to be done only on the code that depends on libtorch and not the rest, so I tried several ways to add it, like CMake Add and Remove a Macro definition to compile Shared Library/Executable and Add target properties to an existing imported library in CMake, but I can't get it to work.
target_compile_definitions seems to be available after cmake 3.11 on "IMPORTED targets"(on cmake terminology).
So why the following cmakelist extract doesn't work? (in that case, the normal QT slots code are not properly recognized as a macro):
find_package (Torch REQUIRED PATHS ${Torch_DIR})
add_executable( ${PROJECT_NAME} ${header_files} ${source_files} ${hpp_files} ${moc_list} ${generated_ui_files} ${generated_qrc_files} )
target_link_libraries(${PROJECT_NAME} ${Qt_LINK_LIBRARIES})
#add_definitions(-DQT_NO_KEYWORDS)
target_link_libraries(${PROJECT_NAME} ${TORCH_LIBRARIES})
#remove_definitions(-DQT_NO_KEYWORDS)
target_compile_definitions(torch INTERFACE QT_NO_KEYWORDS)
Possible Solutions
Option 1:
Use QT_NO_KEYWORDS and replace slots and other keywords with their equivalent uppercase macros, e.g. Q_SLOTS.
Option 2:
Don't use QT_NO_KEYWORDS and wrap the parts of your C++ code with conflicting keywords like this:
#undef slots
#include <torch/torch.h>
#define slots Q_SLOTS
Explanations
The INTERFACE keyword in target_compile_definitions() tells CMake that all targets that depend on the torch library need the QT_NO_KEYWORDS macro defined as well. This is why all sources of your executable will be compiled with -DAT_NO_KEYWORDS and the slots keyword will not be defined.
I suppose you tried to fix your problem with the commented out add_definitions()/remove_definitions() calls. Several reason why those don't work as expected:
They only affect compilation not linking. Putting them around target_link_libraries() has no effect.
They manipulate the compile flags of all targets created in the current scope (current CMakeLists.txt), no matter if they were created before or after the command gets invoked, see the docs. This means calling add_definitions() and subsequently remove_definitions() with the same arguments will result in no flags being added at all no matter at which point in your CMakeLists.txt you call them.
You should also note that commands operating on the directory level (add_*/remove_*) are considered "old style" CMake. Modern CMake aims to only operate on the target level (target_* commands). Some more "Modern CMake" suggestions:
Use target_sources() instead of variables like header_files, source_files, etc. to add sources to your targets.
Always use target_link_libraries() with a PRIVATE, PUBLIC or INTERFACE keyword. Excerpt from Craig Scotts Professional CMake book:
The target_link_libraries() command also has a few other forms, some of which have been part of CMake from well before version 2.8.11. [...] Their use is generally discouraged for new projects. The full form shown previously with PRIVATE, PUBLIC and INTERFACE sections should be preferred, as it expresses the nature of dependencies with more accuracy. [...] The above form [(without PRIVATE/PUBLIC/INTERFACE)] is generally equivalent to the items being defined as PUBLIC, but in certain situations, they may instead be treated as PRIVATE. In particular, if a project defines a chain of library dependencies with a mix of both old and new forms of the command, the old-style form will generally be treated as PRIVATE.
I've been able to make a fair amount of progress in trying to add Bazel build files to enable the building of the gennorm2 tool in ICU. Here is my work-in-progress PR using the Bazel target //icu4c/source/tools/gennorm2.
I'm currently getting stuck when running bazelisk build //icu4c/source/tools/gennorm2 --verbose_failures --sandbox_debug with these errors.
They reference functions defined in urename.h. As I understand it, urename.h is also used to rename certain functions by appending a suffix with the version number (_68), but I defined a preprocessor constant U_DISABLE_RENAMING to disable that specific behavior. This only had the effect of changing the names of the undefined function names in the error output, but otherwise not changing it (ex: errors now complain of u_errorName instead of u_errorName_68).
The part that puzzles me is why the error output claims that these symbols are not found. As you can see, the target //icu4c/source/tools/gennorm2 depends on //icu4c/source/common:platform, which in turn depends on //icu4c/source/common:headers, which includes the field hdrs = glob(["unicode/*.h", "unicode/*.h",]), which should be matching
/icu4c/source/common/unicode/urename.h.
In case it helps, this is the verbose log output when running make VERBOSE=1 using the current autotools-based configure + make build on a fresh checkout of ICU.
A teammate was able to take a look and help me reason through the errors and ultimately fix them.
The first thing is to acknowledge that it is indeed a linker error, which can see by noticing the error message references the linker program ld.
This is important because we previously spent time in the wrong place by debugging the compile configs as if the problem happened during the compile phase before the linker phase. (But I learned about one way to debug compile problems is taking the raw GCC command given by --verbose_failures --sandbox_debug and replacing -c with -E and changing the argument of -o to a .txt file in /tmp to save the output what the compiler sees for that file after all the includes are recursively inlined). This means that my attempts to solve the problem by specifying preprocessor defines for the compile-phase were misguided.
The project's documentation on dependencies revealed that I had mis-specified a dependency on one of the targets to specify only the headers (//icu4c/source/common:headers) instead of the relevant definitions and headers (//icu4c/source/common:platform).
After doing that, we solved another problem that was small and interesting. The gennorm2 target depends on code to get the current year (ex: for printing out help messages that include the copyright statement with the year range). As an i18n library, ICU has code to get that, somewhere in //icu4c/source/i18n:icu4ci18n. This creates an excessive amount of code dependencies for an isolated use case (and will cause problems for follow-on work), so we replaced the block of code in gennorm2 calling those calendar year fns (ucal_open, ucal_getNow, ucal_setMillis, ucal_get, ucal_close) with the libc date library function to give us the year as a number, and added linkopts = ["-ldl"] to link in the dl date library.
I have a Qt project which requires a library (gphoto2) to enable some features that are not essential. I'd like to add some sort of configuration option to my qmake or make call to enable features using this library, so I can compile without it being installed.
What is the best way to configure something like this?
I guess I need some way to add a define based on a compiler parameter, which I can query in my code using #ifdef ...
I assume you use make (without qmake). It is reasonable and quite easy to use GNU make (alone) on Qt projects. You could use some other build automation tool like ninja.
Then you could decide to enable that Gphoto feature by compiling your code with -DWITH_GPHOTO and using #if WITH_GPHOTO in your C++ code.
You would compile by adding
CXXFLAGS+= -DWITH_GPHOTO
in your Makefile
I won't call that a "custom compiler flag" (e.g. like GCC plugins can provide) but a preprocessor flag. It is pretty standard practice.
Maybe you also want to pass such flags to moc. Then your Makefile is running moc thru some rule and command, which you could tailor too.
BTW, you might consider GNU autoconf or some other Makefile generator like cmake. I don't think you should spend too much time on these...
PS. I don't know how that idea translates into qmake and leave you to find out.
Assuming, you are using qmake, you can add a preprocessor definition depending on the existence of a file or an environment variable.
You could add a qmake project for compiling your external library and place it relative to your own project by default.
LIBGPHOTO2_PATH = $$getenv(LIBGPHOTO2PATH)
isEmpty(LIBGPHOTO2_PATH): LIBGPHOTO2_PATH = ../../libgphoto2
exists($$LIBGPHOTO2_PATH/libgphoto2.pri): include($$LIBGPHOTO2_PATH/libgphoto2.pri)
In libgphoto2.pri you add a preprocessor definition to indicate the presence of libgphoto2, add include and linker paths etc.:
DEFINES += WITH_LIBGPHOTO2
In the code of your dependent project, you check for the presence using #ifdef.
Instead of creating a qmake-project to compile, you could also check for the presence of the compiled library at a given path and set values directly (I don't know how libgphoto compiles, so I assume a default directory structure with include/, lib/ etc):
LIBGPHOTO2_PATH=$$getenv(LIBGPHOTO2PATH)
isEmpty(LIBGPHOTO2_PATH): LIBGPHOTO2_PATH = ../../libgphoto2
exists($$LIBGPHOTO2_PATH/include) {
DEFINES += WITH_LIBGPHOTO2
INCLUDEPATH += $$LIBGPHOTO2_PATH/include
LIBS += -L$$LIBGPHOTO2_PATH/lib -lgphoto2
}
You should however consider to move to something more modern like qbs, which is a lot faster, more flexible and easier to read.
I have the following situation: a static library MyStaticLib depending on several libraries of the FFmpeg project (libavformat etc.).
The FFmpeg libraries were linked (not by me) with the "/SAFESEH:NO" option, which means that any image that links to them (via their import libraries) must also be linked with the same option (failure to do so makes the linker abort with "LNK2026: module unsafe for SAFESEH image").
I've tried everything I could think of, but I haven't found a way to attach that option to my MyStaticLib in a way that would make it propagate to the consumer.
This seems strange, because CMake does provide the means for compiler options to propagate to consumers: the command target_compile_options() used with the PUBLIC option does exactly that.
Is there no similar feature for linker flags?
VC++ compiler and linker accept both
a forward slash (/) and a dash (–) as an option specifier.
As mentioned by #tsyvarev, CMake may have problems with forward slash, treating it as a path separator.
Therefore you need to use the following command to add a linker option to MyStaticLib target and propagate the option to the MyStaticLib consumers:
target_link_libraries(MyStaticLib PUBLIC "-SAFESEH:NO")
or if your build config supports other compilers as well:
target_link_libraries(MyStaticLib PUBLIC "$<$<CXX_COMPILER_ID:MSVC>:-SAFESEH:NO>")
Starting with CMake 3.13, you need to use target_link_options() instead:
target_link_options(${CMAKE_PROJECT_NAME} PUBLIC "$<$<C_COMPILER_ID:MSVC>:-SAFESEH:NO>")
Tested with CMake 3.16.2 and MSVC2019.
I am trying to include the UIAutomation.h library in my Code::Blocks client but I think I am doing something wrong. I just typed:
#include <UIAutomation.h>
at top of my program where all my other headers are and I get this error message right away when I compile:
fatal error: UIAutomation.h: No such file or directory
I am a bit of a newb with these things, and I saw some people talk online about a "linker". If a linker has anything to do with me being able to use the UI Automation library, please let me know what is a linker and how do I use it? Otherwise, please let me know what you think I could be doing wrong.
ohh ok so I can do like #include "c:\programfiles\...\UIAutomation.h"??.. do I have to include the <>? like: #include <"c:\blah\blah"> or #include "c:\blah\blah"??
Yes you can do that, but that's very probably a bad idea!
You should better use the -I option of the actual compiler to specify where to search for additional (besides standard) include files:
-I"c:\programfiles\UIAutomation\include"
Also you'll need to set the -L option for the linker to specify where to find the corresponding libraries for UIAutomation:
-L"c:\programfiles\UIAutomation\lib"
and the library itself with the -l<lib> option:
-lUIAutomation
The latter name depends which library files are actually present in the directory specifed with the -L option. The above sample expects to find a file named libUIAutomation.a or libUIAutomation.lib there.
I'm not really experienced with the codeblocks IDE, but from what I remember it allows you to set these options in the project settings.
NOTE:
All the specific option references given above, refer to the actual toolchain used for your codeblocks project. These will apply for the most commonly used toolchains (e.g. like GCC), but may vary for different ones. Though, there- will be certainly equivalent options for the compiler and linker tool used.