add_custom_command(
OUTPUT …
COMMAND …
IMPLICIT_DEPENDS C “C:/WS/project1/timer_x.c”
VERBATIM
)
but I cannot get the dependencies scanner to work correctly
What I want is, if any headers declared (including “recursive header”, ie. header included by an header) in timer_x.c changes, the custom command should run
But it does not work!
I am using GNU Makefiles
I am trying to replace existing Eclipse CDT Builder with CMake
Based on the file extension (.c), I guess you want to compile C code. If so, you should not use add_custom_command to do that at all.
What do you want to compile that C code into? An executable? Then, you should use add_executable. A shared or static library? Then, you should use add_library. A loadable module (also known as “plugin” in some communities)? Then, you should use add_library as well.
Dear Alain,
Yes I want to compile C code into executable
What I want to achieve is, if timer_x_if.h is modified, “make all” should re-build incrementally the project (without running CMake again). Similarly, if any other *.h files (included by timer_x_if.h) is modified, “make all” should re-build incrementally the project as well
add_custom_command(
OUTPUT “${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/My_Project.dir/timer_x/src/timer_x.c.obj”
COMMAND #compiler command to output timer_x.c.obj based on timer-x.c
COMMENT “\n SHOULD only run if timer_x_if.h changes” IMPLICIT_DEPENDS C ${CMAKE_CURRENT_SOURCE_DIR}/timer_x/src/timer_x.c
VERBATIM
)
add_custom_target(
header-target
DEPENDS “${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/My_Project.dir/timer_x/src/timer_x.c.obj”
COMMENT “\n SHOULD only run if timer_x_if.h changes”
VERBATIM
)
Nothing more. CMake and make should take care of dependency tracking.
It will track changes in *.c file, but not *.h file. Which means if any of the *.c file is modified, incremental compilation will happen to that *.c file only
But it just does not track changes to *.h file. If any of the *.h changes, “make all” does not re-build
I learnt somewhere (and verified it myself) that even if I add *.h in add_executable(…), the build target is not sensitive to changes in *.h file
Of course I can do a “make clean” before build, but that defeat the purpose of being able to compile incrementally with the use of makefile
I don’t think you necessarily missed something, but there’s definitely something wrong with your setup, because normally, the way CMake handles inclusion dependencies works. There must be something strange in your CMakeList, in the source files, or in your toolchain. Can you provide a self-contained example which reproduces the incorrect behaviour you observe, so that we could analyse what’s wrong?
The things to include in the example would be:
The CMakeLists.txt file
The source files & header files
The CMakeCache.txt file generated in your build directory
A description of your platform & build tools
Any other necessary files
Ideally, minimise the example by removing anything which can be removed without the bug disappearing.
The problem you’re experiencing sounds strange; I’d love to get to the bottom of it if my skills allow.
I found that my tool (Tensilica Clang) wasn’t for some reason being recognized by CMake as Clang, so it wasn’t generating dependencies correctly.
When you do a reconfig and it tests for the C/C++ compilers, does it say “compiler unknown” or does it give a version and manufacturer of the compiler?
When you do a reconfig and it tests for the C/C++ compilers, does it say “compiler unknown” or does it give a version and manufacturer of the compiler?
It was able to find the compiler:
– CMAKE_C_COMPILER=C:/xxx/xxx/xxx/bin/xxx.exe
Like others have pointed out that adding timer_x/src/timer_x.c with add_executable should have sufficed. You could try switching to the Ninja generator and see if that gives you better results (as it handles dependency tracking differently).
I mean, what does the Cmake show when it runs the test compilation to identify the C compiler?
Mine shows this:
[cmake] – Selecting Windows SDK version 10.0.17763.0 to target Windows 10.0.19041.
[cmake] – The C compiler identification is MSVC 19.16.27025.1
[cmake] – The CXX compiler identification is MSVC 19.16.27025.1
[cmake] – Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe
[cmake] – Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe – works
[cmake] – Detecting C compiler ABI info
[cmake] – Detecting C compiler ABI info - done
[cmake] – Detecting C compile features
[cmake] – Detecting C compile features - done
If CMake can’t identify your compiler, it doesn’t know how to get the implicit dependencies, so it doesn’t.
Ok, you are cross compiling, then. (Compiling in windows for the Renesas part). Cross compiling with CMake is not the most documented of features, unfortunately.
I’m assuming Renesas tools are GCC based. I don’t know exactly how to help you since I haven’t ever compiled for Renesas, but make sure you have CMAKE_C_COMPILER, CMAKE_CXX_COMPILER and CMAKE_ASM_COMPILER defined in your toolchain file.
Here’s our IAR for ARM toolchain file:
### BEGIN CMAKE_TOOLCHAIN_FILE
set(CMAKE_SYSTEM_NAME iar)
set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES "TARGET_PROCESSOR;CONFIG_TARGET;EW_ROOT_DIR")
# Set the EW installation root directory
#(Avoid spaces in the path or you need to escape them)
# This magic command will find iccarm.exe in the system PATH
find_program(ICCARM_EXE iccarm.exe)
# Trim the trailing /arm/bin/iccarm.exe from the above and make this EW_ROOT_DIR
string(REGEX REPLACE "/arm/bin/iccarm.exe$" "" EW_ROOT_DIR ${ICCARM_EXE})
# Fall back to the legacy location if find_program didn't find it
if(NOT EXISTS ${EW_ROOT_DIR})
set(EW_ROOT_DIR "c:/ew/arm-805")
endif()
# Compiler flags needed to compile for this CPU
set(CPU_FLAGS "--cpu ${TARGET_PROCESSOR}")
# Set up the CMake variables for compiler and assembler
# (The reason for both C and CXX variables is that CMake
# treats C and C++ tools individually)
set(CMAKE_C_COMPILER "${EW_ROOT_DIR}/arm/bin/iccarm.exe" "${CPU_FLAGS} -e --dlib_config full")
set(CMAKE_CXX_COMPILER "${EW_ROOT_DIR}/arm/bin/iccarm.exe" "${CPU_FLAGS} --dlib_config full")
set(CMAKE_ASM_COMPILER "${EW_ROOT_DIR}/arm/bin/iasmarm.exe" "${CPU_FLAGS} ")
### END CMAKE_TOOLCHAIN_FILE
Some of this probably isn’t useful to you, but it’s a template that is working for me when we’re cross compiling using the IAR tools for ARM.