Discussion:
[CMake] CMAKE_*_IMPLICIT_INCLUDE_DIRECTORIES with MinGW
Olivier Croquette
2018-11-03 20:41:03 UTC
Permalink
Hi,


I got recently build errors when introducing external dependencies in my project, the reason is that those components re-add standard SYSTEM include search paths, which changes the search order and causes #include_next to fail. The typical error message is:
C:\...\lib\gcc\x86_64-w64-mingw32\7.2.0\include\c++\cstdlib:75: error: stdlib.h: No such file or directory

at #include_next





The following bug report against GCC describes the same issue independently of CMake, and apparently no improvement is to be expected from the compiler itself:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129


So I rolled up my sleeves and implemented the following solution in CMake. It calls the preprocessor to get the standard include search paths and adds them to CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES and CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES.
When a project or an external component tries to add them, CMake ignores this, and the search order stays unharmed.

if("${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES}" STREQUAL "")
# Run the preprocessor in verbose mode on an empty input
execute_process(
COMMAND
"${CMAKE_CXX_COMPILER}"
"-E"
"-Wp,-v"
"-"
INPUT_FILE "NUL" # Special Windows file, equivalent to /dev/null
OUTPUT_VARIABLE _mingw_cpp_out # Capture stdout
ERROR_VARIABLE _mingw_cpp_error # Capture stderr
)

# Create list of lines from stderr output:
string(REGEX REPLACE ";" "\\\\;" _mingw_cpp_error "${_mingw_cpp_error}")
string(REGEX REPLACE "\n" ";" _mingw_cpp_error "${_mingw_cpp_error}")

# Look for this text block and gather the paths:
# #include search starts here:
# C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/include
# C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/include-fixed
# C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/include
# End of search list.
set(_mingw_cpp_list)
foreach(_mingw_cpp_line ${_mingw_cpp_error})
if("${_mingw_cpp_line}" MATCHES "#include search starts here:")
# Block starts
set(_mingw_cpp_state "ON")
elseif("${_mingw_cpp_line}" MATCHES "End of search list.")
# Block ends
set(_mingw_cpp_state "OFF")
elseif("${_mingw_cpp_state}")
# Within block
# Clean up and beautify the path
string(STRIP "${_mingw_cpp_line}" _mingw_cpp_line)
get_filename_component(_mingw_cpp_line ${_mingw_cpp_line} REALPATH)
list(APPEND _mingw_cpp_list ${_mingw_cpp_line})
endif()
endforeach()

# Set the list in the cache, so that we don't have to run the external process again
set(CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES ${_mingw_cpp_list} CACHE INTERNAL "List of MinGW system include paths")
endif()

list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES ${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES})
list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES ${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES})







My question is: shouldn't this be done within the standard CMake distribution, when using any GCC based compiler?





Olivier
Olivier Croquette
2018-11-08 06:36:26 UTC
Permalink
Hi everyone,

any feedback on this?
As a summary, it's about adding the default include paths of GCC to the
variables "CMAKE_*_IMPLICIT_INCLUDE_DIRECTORIES" to avoid CMake modules
or scripts to mess up with them, more specifically with their order.

Cheers,
Olivier
Post by Olivier Croquette
Hi,
I got recently build errors when introducing external dependencies in
my project, the reason is that those components re-add standard SYSTEM
include search paths, which changes the search order and causes
error: stdlib.h: No such file or directory|
|at #include_next
|
|
|
||
The following bug report against GCC describes the same issue
independently of CMake, and apparently no improvement is to be
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
So I rolled up my sleeves and implemented the following solution in
CMake. It calls the preprocessor to get the standard include search
paths and adds them to CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES and
CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES.
When a project or an external component tries to add them, CMake
ignores this, and the search order stays unharmed.
if("${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES}" STREQUAL "")
    # Run the preprocessor in verbose mode on an empty input
    execute_process(
        COMMAND
            "${CMAKE_CXX_COMPILER}"
            "-E"
            "-Wp,-v"
            "-"
        INPUT_FILE "NUL" # Special Windows file, equivalent to /dev/null
        OUTPUT_VARIABLE _mingw_cpp_out # Capture stdout
        ERROR_VARIABLE _mingw_cpp_error # Capture stderr
    )
    string(REGEX REPLACE ";" "\\\\;" _mingw_cpp_error
"${_mingw_cpp_error}")
    string(REGEX REPLACE "\n" ";" _mingw_cpp_error "${_mingw_cpp_error}")
    # C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/include
    # C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/include-fixed
    #
C:/..../bin/../lib/gcc/x86_64-w64-mingw32/7.2.0/../../../../x86_64-w64-mingw32/include
    #   End of search list.
    set(_mingw_cpp_list)
    foreach(_mingw_cpp_line ${_mingw_cpp_error})
        if("${_mingw_cpp_line}" MATCHES "#include  search starts here:")
            # Block starts
            set(_mingw_cpp_state "ON")
        elseif("${_mingw_cpp_line}" MATCHES "End of search list.")
            # Block ends
            set(_mingw_cpp_state "OFF")
        elseif("${_mingw_cpp_state}")
            # Within block
            # Clean up and beautify the path
            string(STRIP "${_mingw_cpp_line}" _mingw_cpp_line)
            get_filename_component(_mingw_cpp_line ${_mingw_cpp_line}
REALPATH)
            list(APPEND _mingw_cpp_list ${_mingw_cpp_line})
        endif()
    endforeach()
    # Set the list in the cache, so that we don't have to run the
external process again
     set(CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES ${_mingw_cpp_list}
CACHE INTERNAL "List of MinGW system include paths")
endif()
list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES
${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES})
list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
${CMAKE_MINGW_IMPLICIT_INCLUDE_DIRECTORIES})
My question is: shouldn't this be done within the standard CMake
distribution, when using any GCC based compiler?
Olivier
Alan W. Irwin
2018-11-08 09:55:13 UTC
Permalink
Post by Olivier Croquette
Hi everyone,
any feedback on this?
As a summary, it's about adding the default include paths of GCC to the
variables "CMAKE_*_IMPLICIT_INCLUDE_DIRECTORIES" to avoid CMake modules or
scripts to mess up with them, more specifically with their order.
Hi Olivier:

I am afraid I cannot help you directly with your specific question
because I have no access to the Microsoft version of Windows, and it
has been a while since I worked with the Wine version of Windows.
However, for the sake of those who might be able to help you, I
suggest you clarify exactly what you mean by "MinGW". For example,
some possibilities are

1. MinGW, the traditional gcc variant for Windows. This platform uses
the CMake generator "MinGW Makefiles" and the MinGW version of GNU
make.

2. MinGW-w64, a successor (with different developers, see
<https://sourceforge.net/p/mingw-w64/wiki2>) to MinGW. This
platform uses the CMake generator "MinGW Makefiles" and the
MinGW-w64 version of GNU make (see
<https://sourceforge.net/p/mingw-w64/wiki2/Make/>)

3. MinGW/MSYS which combines the traditional gcc variant for Windows
and a traditional Unix-like variant for Windows where MSYS is
developed by the same group of developers as MinGW. This platform
uses the CMake generator "MSYS Makefiles" and the MSYS version of
GNU make.

4. MinGW-w64/MSYS2 a successor to MinGW/MSYS where the MSYS2
developers are a different group (See
<https://github.com/msys2/msys2/wiki>) than the MinGW-w64
developers and the MSYS developers. This platform uses the CMake
generator "MSYS Makefiles" and the MSYS2 version of GNU make.

5. A slight variant of 4. which uses the "Unix Makefiles" generator.

The reasons these platform distinctions are important for your
question is the issue you have found might not be an issue for
some/most of them. For example, years ago I did do comprehensive
(including static linking) tests of PLplot on platform 3 for the Wine
version of Windows, and I do not recall encountering the issue you
have described. And my friend and PLplot colleague Arjen Markus who
comprehensively tests PLplot on platform 5 on a regular basis has also
never run into this issue according to the comprehensive test reports
he has sent to me over the years including one such report just last
week.

Of course, PLplot comprehensive tests might not expose the issue you
have discovered so I suggest you provide a self-contained minimal
CMake-based project (minimal C source code + CMake build system to
build it) which demonstrates the issue you have found on at least one
of the above platforms. Once you supply that, others here can
conveniently use that test project to verify (or not) the issue on any
of the above 4 platforms.

Good luck with your further investigations into this issue!

Alan
__________________________
Alan W. Irwin

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake
Loading...