Search code examples
pythonc++visual-studioswig

Swig defines SWIG_init with a hyphen in debug mode on windows, resulting in autogenerated C++ code that is invalid


On Windows, I am using cmake, swig, and visual studio to build a python wrapper for my library. In Release mode everything works fine. In Debug, the generated code contains this line:

#define SWIG_init PyInit__myproject-gd

So Debug appends the -gd which is not there in Release. The build goes on to use that symbol as a function name, which is not valid C++ because a hyphen is not allowed in an identifier. And so this line...

SWIG_init(void) {

...causes the build to fail with this error message:

C:\xxx\myprojectPYTHON_wrap.cxx(807935,1): error C2143: syntax error: missing ';' before '-'
C:\xxx\myprojectPYTHON_wrap.cxx(807935,1): error C2059: syntax error: '-'
C:\xxx\myprojectPYTHON_wrap.cxx(807935,17): error C2143: syntax error: missing ';' before '{'
C:\xxx\myprojectPYTHON_wrap.cxx(807935,17): error C2447: '{': missing function header (old-style formal list?)

How do I fix this?

Edit:

In release, the swig command emitted by cmake includes:

-interface _myproject

For debug it says:

-interface _myproject-gd

So in the c++ code autogenerated by swig I get a function called _myproject in release but _myproject-gd in debug.

In this file:

C:\Program Files\CMake\share\cmake-3.26\Modules\UseSWIG.cmake

I see:

# This makes sure that the name used in the proxy code
# matches the library name created by CMake
list (APPEND SWIG_MODULE_${name}_EXTRA_FLAGS "-interface" "$<TARGET_FILE_PREFIX:${target_name}>$<TARGET_FILE_BASE_NAME:${target_name}>")

I have debugged that cmake generator expression and of course it evaluates to _myproject in release and _myproject-gd in debug.

In this file:

C:\repos\myproject\cmake\commonSettings.cmake

I see:

    if("${MSVC_RUNTIME}" STREQUAL "static")
        set(CMAKE_DEBUG_POSTFIX "gd")
    else()
        set(CMAKE_DEBUG_POSTFIX "-gd")
    endif()

Removing that hyphen fixes the compile error but breaks other things. I'm not certain, but it seems to me that the cmake configuration for swig is misappropriating a cmake variable that is intended to be used in a file (lib) name and is instead incorporating it into the name of a C++ function. So you add a hyphen to that cmake variable, thinking that your lib name will contain a hyphen, and then your autogenerated swig code breaks. I might be wrong, I am still digging.

Edit #2:

I notice that UseSWIG.cmake only sets the -interface flag if it has not already been set. So, before calling swig_add_library, if I do something like this...

list (APPEND SWIG_MODULE_myproject_EXTRA_FLAGS "-interface" _myproject)

...it appears to fix the problem. I can't yet be sure because my build still fails later with what appears to be a separate, unrelated problem.


Solution

  • Our site sometimes populates CMAKE_DEBUG_POSTFIX with a value containing a hyphen e.g. "-gd". Function swig_add_library() (defined in module UseSWIG.cmake) misappropriates this variable in two ways:

    1. It uses the variable as part of the name of a function in the autogenerated C source code. The hyphen results in invalid C.
    2. It uses the variable as part of the package name and a hyphen results in the package not getting loaded at runtime.

    The workaround for us was to unset CMAKE_DEBUG_POSTFIX before calling swig_add_library() and restore CMAKE_DEBUG_POSTFIX after (because it is required by subsequent calls to target_link_libraries):

    set(TEMP_CMAKE_DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
    unset(CMAKE_DEBUG_POSTFIX)
    swig_add_library(myproject TYPE MODULE LANGUAGE python SOURCES myproject.i)
    set(CMAKE_DEBUG_POSTFIX ${TEMP_CMAKE_DEBUG_POSTFIX})