I would like to add some compiler and linker flags to the default C++ toolchain, so that all the targets I build (local or imported) share them.
I know that can define my own toolchain, but I don't want to do that as it's very complicated and easy to get wrong.
Ideally I would like something like this:
cc_toolchain = cc_default_toolchain()
cc_toolchain.copts = [...]
cc_toolchain.linkopts = [...]
Also, I don't want to set global flags in the .bashrc file, as it's hard to configure per platform and it's not easy to share among different repositories.
Thanks!
You could set --cxxopt and --linkopt in a shared .bazelrc file that you reference from the different projects (as sub-module or similar) or import in the workspace's local .bazelrc file.
I think you have to copy the default generated toolchain into your project and make modifications in it.
You'd run bazel info to locate your output_base directory, and find the toolchain files there.
Source: https://groups.google.com/g/bazel-discuss/c/N1qvsGMJoAE
Related
I have a c_cpp_properties.json in my .vscode folder, and it's working properly. However, there is a line in it that is system specific:
"compilerPath": "~/.espressif/tools/xtensa-esp32-elf/esp-2021r2-patch5-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc"
And while I can assume default install for the .espressif tools, unfortunately the distributor of the toolchain changes the path on every version (I.e. .../esp-2021r2-patch5-8.4.0/...)
I'm wondering if there's a way to use something like
which xtensa-esp32-elf-gcc
in the json so this will update with the toolchain updates?
I'll start by mentioning that the most easiest way to do this is via the creation / or update of a symbolic link in /usr/bin as rioV8 mentioned in the comments.
The command which xyz will look through the path environment variable anyway, so unless you have a symbolic link under one of the paths listed in path, it won't be as easy.
That being said I can imagine that you may want to (for some specific reason) switch the compiler from time to time (for example when debugging historic versions) and for example you do this by having predefined environments where you specify the path.
So to do this I looked into how VS Code's CMake Tools parse the c_cpp_properties.json file and passing anything other than a string to compilerPath doesn't look like a good idea, however if we take a look at Lines 430-451 of this file. We can see what has priority when deciding which CXX / C compiler to use.
Based on that - what you can do is go to your CMakeLists.txt file and before you define the project you can add this snippet for your own CXX search:
execute_process(COMMAND your_script_or_command_to_get_cxx_path_here RESULT_VARIABLE which_cxx OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CMAKE_CXX_COMPILER ${which_cxx})
project(TEST)
#... rest of your CMakeLists.txt
For example:
execute_process(COMMAND which g++ RESULT_VARIABLE which_cxx OUTPUT_STRIP_TRAILING_WHITESPACE)
After you clean and generate a new build folder, it should override whatever is in c_cpp_properties.json
But in all honesty, I would just stick to the symbolic link.
I have a CMake project that uses an external tool to build special libraries for a certain platform. Running this tool uses a "config file" to generate several files that are injected into the compiler and linker options when the final program is built:
An object library
A linker command file that links in several pre-compiled libs and the above object library
A makefile options file that sets various platform compiler options
whenever any of these files change, the main program must be entirely rebuilt, as they are intrinsic parts of the program and involve things like compiler flags and system includes.
So far, I have something like this, which appears to be a recommended way:
# run the external build tool to generate platform libs
# and compiler/linker option files
add_custom_command(
OUTPUT ${LINKER_CMD_FILE} ${COMPILER_OPTS_FILE} ${PLATFORM_OBJECT_LIB}
COMMAND "${EXTERNAL_BUILD_TOOL}"
ARGS --config ${CFG_FILE}
DEPENDS ${CFG_FILE}
COMMENT "Invoking external build tool for ${CFG_FILE}"
)
add_custom_target(platform_libs
DEPENDS ${LINKER_CMD_FILE} ${COMPILER_OPTS_FILE} ${PLATFORM_OBJECT_LIB}
)
....
add_executable(main_prog
main.c
)
# whenever any of these change, rebuild
add_dependencies(main_prog platform_libs)
# add the platform compiler opts from the generated file
target_compile_options(main_prog PRIVATE
#${COMPILER_OPTS_FILE}
)
This is also pretty much what is done in this question.
When I change the config file, the platform_libs target runs and generates the library and other files as needed. However, although running make main_prog does trigger the build of the platform_libs correctly, it does not appear to "notice" any changes and therefore concludes it doesn't need to actually re-build the main program.
I can always run make clean, but it's not great to have CMake totally blind to fundamental system libraries changing.
How can I force main_prog to rebuild if platform_libs has run?
[This answer's central method comes from #KamilCuk's answer in the comment of the question].
The trick is to use one of:
Set the LINK_DEPENDS property on the downstream target (main_prog in the example) - this means if the file in this property changes, a re-link will be performed.
Set the OBJECT_DEPENDS on every source used for main_prog.
In my case, because the ${COMPILER_OPTS_FILE} affects every file's compilation, I needed the OBJECT_DEPENDS method. If you do this you don't really need LINK_DEPENDS since you'll recompile your sources and re-link anyway, but I did both for clarity of meaning. In theory you could engineer a situation where the linker command file changes, but not the compiler opts, in which case you might miss a re-link.
In my case, I needed to do this for not only main_prog but also all the other libraries main_prog used, so I stored the linker command files and the compiler opts file as target properties on the platform_libs target:
set_property(TARGET platform_libs
PROPERTY MY_LINKER_CMD_FILE ${LINKER_CMD_FILE}
)
set_property(TARGET platform_libs
PROPERTY MY_COMPILER_OPTS_FILE ${COMPILER_OPTS_FILE}
)
This means it's easy to pull them out later, without having to know the exact file names (or even have access to the variables themselves):
# Retrieve the previously-stored options
# To do this, we only need the target name and the (fixed) property name
get_target_property(MY_LINKER_CMD platform_libs MY_LINKER_CMD_FILE)
get_target_property(MY_COMPILER_OPTS platform_libs MY_COMPILER_OPTS_FILE)
set_target_properties(main_prog PROPERTIES
LINK_DEPENDS ${MY_LINKER_CMD}
)
# Also set as the linker cmd on the linker command line
# This depends on the linker, for GCC it's -Wl,T<file>
target_link_libraries(main_prog PRIVATE
-Wl,-T${MY_LINKER_CMD}
)
# these are the sources that depend on the opts file
get_target_property(MAIN_SRCS main_prog SOURCES)
# set the dependency of source files on platform_libs
set_property(SOURCE ${MAIN_SRCS}
PROPERTY OBJECT_DEPENDS ${MY_COMPILER_OPTS}
)
# Set as a compiler opt file
# For GCC: #<opt_file>
target_compile_options(${TARGET_TO_COMPILE} PRIVATE
#${MY_COMPILER_OPTS}
)
# make sure the platform_libs is a dep
# or the compiler opts and linker files won't be generated
add_dependencies(main_prog platform_libs)
Notably, in this Cmake code, the project names main_prog and platform_libs can be variables, and then you can make the whole thing into a function that just needs those two project names. This makes it easy to reuse the code for compiling libraries against platform_libs library.
I am trying to setup a toolchain file for cross compilation with CMake 3.12.0 version.
My object files have a different extensions than .obj on Windows and .o in UNIX.
Thus, I set my CMAKE_LANG_OUTPUT_EXTENSION to .src.
Unfortunately, this variable is overwritten by CMakeCInformation.cmake file in these lines:
# some compilers use different extensions (e.g. sdcc uses .rel)
# so set the extension here first so it can be overridden by the compiler specific file
if(UNIX)
set(CMAKE_C_OUTPUT_EXTENSION .o)
else()
set(CMAKE_C_OUTPUT_EXTENSION .obj)
endif()
If I comment these lines my configurations will work and the right object extension will be used.
I think my toolchain file is configured so that CMake will not execute its internal compiler checks.
This is how my toolchain file entry lines look:
SET(CMAKE_SYSTEM_NAME Generic)
INCLUDE(CMakeForceCompiler)
SET(CMAKE_C_COMPILER_FORCED TRUE)
SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
#other compiler configuration lines here
SET(CMAKE_C_OUTPUT_EXTENSION .src)
SET(CMAKE_ASM_OUTPUT_EXTENSION .o)
SET(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
SET(CMAKE_ASM_OUTPUT_EXTENSION_REPLACE 1)
I know CMakeForceCompiler is depreciated and CMAKE_TRY_COMPILE_TARGET_TYPE should be used that is why both are there.
I am telling CMake about my toolchain file using -DCMAKE_TOOLCHAIN_FILE
Can you please help me figure out what I am doing wrong?
EDIT: I was also trying to CACHE the value of CMAKE_C_OUTPUT_EXTENSION. At least for me this didn't work.
Add SET(CMAKE_C_OUTPUT_EXTENSION .src) in the CMakeLists.txt file after the project command not in the toolchain file. This should get you the desired behavior (as it should override the values set by CMakeCInformation and any other module scripts).
The toolchain file is used for setting basic toolchain information on where the compiler is and some basic settings. Other variables need to be setup afterwards by custom compiler or platform files that can be included via CMAKE_USER_MAKE_RULES_OVERRIDE.
From CMake issue 18713: "This issue has been reported before and it was mentioned that the toolchain file isn't where these kinds of things should be set for more complicated toolchains."
CMake issue 398139 "Toolchain files should not be setting things like this. ... The output extension should be specified by compiler or platform information files that are loaded by CMakeCInformation after the defaults here are set."
In my Makefile I have
CC=g++
When I do mgrep gcc, I have several versions listed like:
gnu/gcc/4.2.1
gnu/gcc/4.7.3
etc
I can do a module load to change my gcc version.
Now suppose I want to use multiple versions simultaneously in different makefiles, how do I do it?
The module system is basically just setting up a path to the requested module. If you want a particular compiler in a particular makefile, then you can do three things:
Expect the user of the makefile to load the correct version before calling Make. Possibly combined with some condition based on gcc -v|grep ${GCC_VERSION} to check that it's the right version.
Perform module load gnu/gcc/${GCC_VERSION} inside your makefile.
Use CC=/somewhere/path-to-gcc-version/bin/g++ instead of CC=g++.
Personally, I prefer 1 or 3. You can find out what the path is by doing module load ... and then which g++.
[By the way, I would use CXX=g++ and CC=gcc - assuming you are not compiling files called *.c as C++-code]
Over the years my projects use more and more external libraries, and the way I did it starts feeling more and more awkward (although, that has to be said, it does work flawlessly). I use VS on Windows, CMake on others, and CodeComposer for targetting Digital Signal Processors (DSPs) on Windows. Except for the DSPs, both 32bit and 64bit platforms are used.
Here's a sample of what I am doing now; note that as shown, the different external libraries themselves are not always organized in the same way. Some have different lib/include/src folders, others have a single src folder. Some came ready-to-use with static and/or shared libraries, others were built
/path/to/projects
/projectA
/projectB
/path/to/apis
/apiA
/src
/include
/lib
/apiB
/include
/i386/lib
/amd64/lib
/path/to/otherapis
/apiC
/src
/path/to/sharedlibs
/apiA_x86.lib -->some libs were built in all possible configurations
/apiA_x86d.lib
/apiA_x64.lib
/apiA_x64d.lib
/apiA_static_x86.lib
/apiB.lib -->other libs have just one import library
/path/to/dlls -->most of this directory also gets distributed to clients
/apiA_x86.dll and it's in the PATH
/apiB.dll
Each time I add an external libary, I roughly use this process:
build it, if needed, for different configurations (release/debug/platform)
copy it's static and/or import libraries to 'sharedlibs'
copy it's shared libraries to 'dlls'
add an environment variable, eg 'API_A_DIR' that points to the root for ApiA, like '/path/to/apis/apiA'
create a VS property sheet and a CMake file to state include path and eventually the library name, like include = '$(API_A_DIR)/Include' and lib = apiA.lib
add the propertysheet/cmake file to the project needing the library
It's especially step 4 and 5 that are bothering me. I am pretty sure I am not the only one facing this problem, and would like see how others deal with this.
I was thinking to get rid of the environment variables per library, and use just one 'API_INCLUDE_DIR' and populating it with the include files in an organized way:
/path/to/api/include
/apiA
/apiB
/apiC
This way I do not need the include path in the propertysheets nor the environment variables. For libs that are only used on windows I even don't need a propertysheet at all as I can use #pragmas to instruct the linker what library to link to.
Also in the code it will be more clear what gets included, and no need for wrappers to include files having the same name but are from different libraries:
#include <apiA/header.h>
#include <apiB/header.h>
#include <apiC_version1/header.h>
The withdrawal is off course that I have to copy include files, and possibly** introduce duplicates on the filesystem, but that looks like a minor price to pay, doesn't it?
** actually once libraries are built, the only thing I need from them is the include files and thie libs. Since each of those would have a dedicated directory, the original source tree is not needed anymore so can be deleted..
Why not use file system links?
ln -s /path/to/apis/apiA/include /path/to/api/include/apiA
Voilá. Similar can be done on Windows, but I don't have the command line handy right now.