I just discovered a copy and paste error in my CMake code:
function(name)
# do something ...
endfunction()
function(name)
# do something else ...
endfunction()
I had copied, renamed and changed the function several times. Apparently I created one copy too many, so that the original function now existed twice. Later I changed one of the two. The error was discovered because the original version was defined after the changed function and therefore my changes had no effect.
Is there a way to detect a double defined function?
It seems that CMake itself has no switch which prevents double function definition. You could run cmake
in a trace mode:
cmake --trace-format=json-v1 --trace-redirect=trace.json <... other params>
The resulted trace.json
file in JSON format will accumulate (amond other info) all calls to 'function' command:
...
{"args":["my_func"],"cmd":"function","file":"/home/tester/tests/cmake/CMakeLists.txt","frame":1,"line":4,"time":1684839183.3986549}
{"args":["my_func"],"cmd":"function","file":"/home/tester/tests/cmake/CMakeLists.txt","frame":1,"line":8,"time":1684839183.398663}
...
Then you may write a script which reads resulted JSON file and finds calls to 'function' command with the same names.
E.g. following jq script:
# Select only functions definitions
map(select(.cmd=="function")) |
# Simplify information to only a function name and its location.
map({"func": .args[0], "file": (.file + ":" + (.line|tostring))}) |
# Group by function names
group_by(.func) |
# Select those groups which have more than one entry.
map(select(length>1))
with usage
jq -s -f <path/to/script> trace.json
could produce such output:
[
[
{
"func": "my_func",
"file": "/home/tester/tests/cmake/CMakeLists.txt:4"
},
{
"func": "my_func",
"file": "/home/tester/tests/cmake/CMakeLists.txt:8"
}
]
]
Note, that the approach above won't work in case CMake will find a syntax error (like with if(AAA AAA)
command) while processing your project: in that case the trace file will be empty.
However, hitting e.g. message(FATAL_ERROR)
won't prevent CMake to trace all commands before the failure.