UseSWIG: 3.20 SWIG_USE_SWIG_DEPENDENCIES and ninja always re-run due to dependency filename mismatch
Using the 3.20 version of UseSWIG I am able to generate dependency files for swig interface files, but with the ninja generator re-running a build always forces a re-compile due to a mismatch in the target filename between the build target and the target in the dependency file.
Minimal reproduction:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(TEST)
set(SWIG_USE_SWIG_DEPENDENCIES TRUE)
# Enabling the following line will prevent the dependency issue.
# set(SWIG_OUTFILE_DIR "frog")
include(FindSWIG)
include(UseSWIG)
find_package(Python3 COMPONENTS Development)
include_directories(${Python3_INCLUDE_DIRS})
swig_add_library(test
LANGUAGE python
SOURCES test.i
)
swig_link_libraries(test "${Python3_LIBRARIES}")
/* test.i */
%module test
/* test.c */
double My_variable = 3.0;
$ cmake --version
cmake version 3.20.0
CMake suite maintained and supported by Kitware (kitware.com/cmake).
$ ninja --version
1.10.2
$ mkdir build
$ cd build
$ cmake -G Ninja ..
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found SWIG: /usr/local/bin/swig (found version "4.0.2")
-- Found Python3: /usr/local/opt/python@3.9/Frameworks/Python.framework/Versions/3.9/include/python3.9 (found version "3.9.2") found components: Development Development.Module Development.Embed
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/dwatson/Desktop/deletetest/build
$ ninja
[3/3] Linking C shared module _test.so
$ ninja -d explain
ninja explain: expected depfile '/Users/dwatson/Desktop/deletetest/build/CMakeFiles/test.dir/test.i.d' to mention 'CMakeFiles/test.dir/testPYTHON_wrap.c', got '/Users/dwatson/Desktop/deletetest/build/CMakeFiles/test.dir/testPYTHON_wrap.c'
ninja explain: CMakeFiles/test.dir/testPYTHON_wrap.c is dirty
ninja explain: CMakeFiles/test.dir/testPYTHON_wrap.c is dirty
ninja explain: CMakeFiles/test.dir/CMakeFiles/test.dir/testPYTHON_wrap.c.o is dirty
ninja explain: _test.so is dirty
[3/3] Linking C shared module _test.so
$ find . -name \*.d
./CMakeFiles/test.dir/test.i.d
$ head -1 ./CMakeFiles/test.dir/test.i.d
/Users/dwatson/Desktop/deletetest/build/CMakeFiles/test.dir/testPYTHON_wrap.c: \
The error is the second run of ninja (ninja -d explain
). At this point nothing has changed in the input files so I would expect ninja to do nothing. Instead it re-generates testPYTHON_wrap.c
using swig. Using the ninja explain debug tool, you can see that ninja is complaining that test.i.d
specifies the target as an absolute path while the build target is specified as a relative path. The head
call confirms that the target in the dependency file is specified using an absolute path.
If I uncomment the set(SWIG_OUTFILE_DIR "frog")
line in CMakeLists.txt
then things work correctly:
$ ninja
[0/1] Re-running CMake...
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/dwatson/Desktop/deletetest/build
[3/3] Linking C shared module _test.so
$ ninja -d explain
ninja: no work to do.
$ head -1 ./CMakeFiles/test.dir/test.i.d
frog/testPYTHON_wrap.c: \
In this case, the second run of ninja doesn't do anything (ninja: no work to do.
) and the head command shows that the target is now specified as a relative path.
I suspect the root cause is line 483 of UseSWIG.cmake (set(outdir ${CMAKE_CURRENT_BINARY_DIR})
). I think changing this to set(outdir "")
would probably fix this specific issue, but I haven't tested it and have no idea if that would break other things. Actually, this wouldn't work because of the way outdir
is combined with other paths... For now setting SWIG_OUTFILE_DIR
is a sufficient workaround.