Indexer problems with mixed C, C++ code [message #1695217] |
Tue, 12 May 2015 18:08 |
Wolfgang Schmieder Messages: 1 Registered: May 2015 |
Junior Member |
|
|
Hello,
I don't expect an answer. I just want to share my experience.
My fix is targeting ECLIPSE-CDT indexer problems with CMake generated projects that use mixed C/C++.
Problem: The Eclipse CDT indexer is showing a lot of unresolved symbol errors, when the CDT 4 project was created with CMake and the code is a mix of C and C++.
The root cause of the problem is the g++ builtin __cplusplus macro that is passed by CMake to the "Contributed PathEntry container" (Refer to Dialog "Project->Properties" item "C/C++ General -> Preprocessor Include Paths, Macros etc." tab "Entries->Setting Entries" for language C and language C++).
The "Contributed PathEntry container" is always the same for C and C++. In mixed C/C++ projects, header files often contain the following lines to let C++ code call the C functions.
#ifdef __cplusplus
extern "C" {
#endif
<...function declarations etc. ...>
#ifdef __cplusplus
}
#endif
Whenever the indexer compiles the code for code analysis, it has the macro __cplusplus set, independent of whether standard C or C++ source files are compiled. This is, because C and C++ use both the common "Contributed PathEntry container" with the __cplusplus macro set (CMake queries the g++ for builtin macros and places it in "Contributed PathEntry container").
The 'extern "C"' confuses the standard C compilation and the indexer is messed up.
Workaround:
I created a CMake file "language_provider.cmake" with a cmake macro "remove_from_SYSTEM_MACROS" that is able wipe out the __cplusplus macro
from the "Contributed PathEntry container".
Optionally it can wipe out all Compiler built in macros. Another cmake macro "remove_from_SYSTEM_MACROS" is able to wipe out all Compiler System Includes (I will explain later why this is useful).
The file "language_provider.cmake" contains an additional function "create_language_provider" that will create Language specific Compiler built in
macros for C and C++ for the "CDT gcc built-in Compiler Settings" - povider. (This was the right provider for my ARM cross gcc).
Do the following to fix the issue:
Include "language_provider.cmake" in your main CMakeLists.txt at a place after the toolchain is determined. In my case that was immediately after the cmake project(..) statement. The CMake fragment looks like this:
set(GCC_PREFIX "C:/gnu/arm-none-eabi/bin/arm-none-eabi-") # This is the location of the compiler with the prefix for my cross tool chain.
set(CXX_STANDARD_FLAG -std=gnu++11) # This is only if you are using C++11, otherwise don't pass a 3rd parameter to function "create_language_provider"
include(language_provider.cmake)
remove_from_SYSTEM_MACROS(CXX "__cplusplus;.*;")
create_language_provider("${CMAKE_BINARY_DIR}/.settings" "${GCC_PREFIX}-" "${CXX_STANDARD_FLAG}")
The above CMake fragment will solve the problem but will also have duplicate Compiler built in macros and duplicate System Include directories.
Duplicates are caused by the 2 providers: "Contributed PathEntry container" and "CDT gcc built-in Compiler Settings".
The duplicates can be avoided if you choose the following cmake code fragment instead:
set(GCC_PREFIX "C:/gnu/arm-none-eabi/bin/arm-none-eabi-") # This is the location of the compiler with the prefix for my cross tool chain.
set(CXX_STANDARD_FLAG -std=gnu++11) # This is only if you are using C++11, otherwise don't pass a 3rd parameter to function "create_language_provider"
include(language_provider.cmake)
remove_from_SYSTEM_MACROS(C)
remove_from_SYSTEM_INCLUDE_DIRS(C)
remove_from_SYSTEM_MACROS(CXX)
remove_from_SYSTEM_INCLUDE_DIRS(CXX)
create_language_provider("${CMAKE_BINARY_DIR}/.settings" "${GCC_PREFIX}-" "${CXX_STANDARD_FLAG}")
Both above solutions fixed my indexer problem almost. In my project, the subdirectories that I had to add with the add_subdirectory() statement were not a real subdirectories of my top level CMakeList.txt directory. So my resulting CDT project contained an extra folder called [Subprojects].
This folder I had to manually add as source folder to the C/C++ Project Paths (Menu "Projects->Properties").
If you are using Cygwin or MinGW gcc instead of a cross compile tool chain, you probably need to replace the following text in function 'create_language_provider':
'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector' by
'org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorCygwin' respectively by
'org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW'
I hope it will work, because I didn't test with Cygwin or MinGW toolchain.
Here is my environment which I used to test my fix:
Windows 7 64 bit
CMake 3.2.2
Arm Gnu Cross Toolchain arm-none-eabi version 4.7 from "GCC Arm Embedded Launchpad".
Eclipse Luna (4.4) with CDT 8.6
And here the contents of the macro 'language_provider.cmake':
# Create language specific (C/C++) compiler built in macros and include paths
message("${MESSAGE_TABS}language_provider.cmake ...")
SET(MESSAGE_TABS "${MESSAGE_TABS}\t")
#Try replacing in function create_language_provider the text:
# 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector' by
# 'org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorCygwin' if you use Cygwin toolchain, respectively by
# 'org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW' if you use MinGW toolchain.
# Note: The above settings for Cygwin / MinGW have not been tested yet.
function(create_language_provider OUTPUT_DIR COMMAND_PREFIX)
set(OUTPUT_FILE ${OUTPUT_DIR}/language.settings.xml)
file(WRITE ${OUTPUT_FILE} "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n")
file(APPEND ${OUTPUT_FILE} "<project>\n")
file(APPEND ${OUTPUT_FILE} "\t<configuration id=\"org.eclipse.cdt.core.default.config.1\" name=\"Configuration\">\n")
file(APPEND ${OUTPUT_FILE} "\t\t<extension point=\"org.eclipse.cdt.core.LanguageSettingsProvider\">\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t<provider copy-of=\"extension\" id=\"org.eclipse.cdt.ui.UserLanguageSettingsProvider\"/>\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t<provider-reference id=\"org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider\" ref=\"shared-provider\"/>\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t<provider class=\"org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector\" console=\"false\" id=\"org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector\" keep-relative-paths=\"false\" name=\"CDT GCC Built-in Compiler Settings\" parameter=\"${COMMAND_PREFIX}\${COMMAND} \${FLAGS} ${ARGV2} -E -P -v -dD "\${INPUTS}"\" store-entries-with-project=\"true\">\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t\t<language-scope id=\"org.eclipse.cdt.core.gcc\"/>\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t\t<language-scope id=\"org.eclipse.cdt.core.g++\"/>\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t</provider>\n")
file(APPEND ${OUTPUT_FILE} "\t\t\t<provider-reference id=\"org.eclipse.cdt.core.PathEntryScannerInfoLanguageSettingsProvider\" ref=\"shared-provider\"/>\n")
file(APPEND ${OUTPUT_FILE} "\t\t</extension>\n")
file(APPEND ${OUTPUT_FILE} "\t</configuration>\n")
file(APPEND ${OUTPUT_FILE} "</project>\n")
endfunction(create_language_provider)
macro(remove_from_SYSTEM_ITEM LANGUAGE ITEM_TYPE CACHE_DOC_STRING)
# message("${MESSAGE_TABS}CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE} = ${CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE}}")
set(TEMP_VAR)
if(${ARGC} LESS 4)
# There is no regular expression, so remove everything
message("${MESSAGE_TABS}wiping ${CACHE_DOC_STRING}")
else(${ARGC} LESS 4)
# The extra argument ist treated as an regular expression. Every match will be removed.
message("${MESSAGE_TABS}Removing ${ARGN} from ${CACHE_DOC_STRING}")
set(TEMP_VAR "${CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE}}")
STRING(REGEX REPLACE "${ARGN}" "" TEMP_VAR "${TEMP_VAR}")
endif(${ARGC} LESS 4)
set(CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE} "${TEMP_VAR}" CACHE INTERNAL "${CACHE_DOC_STRING}")
# message("${MESSAGE_TABS}CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE} = ${CMAKE_EXTRA_GENERATOR_${LANGUAGE}${ITEM_TYPE}}")
endmacro(remove_from_SYSTEM_ITEM ITEM_TYPE)
# Remove a string from C or CXX system include directories.
# The string to be removed is passed as a regular expression within the optional the last argument
# If there is no regular expression, ALL system include directories will be removed.
macro(remove_from_SYSTEM_INCLUDE_DIRS LANGUAGE)
set(system_DOC_STRING "${LANGUAGE} compiler system include directories")
remove_from_SYSTEM_ITEM(${LANGUAGE} _SYSTEM_INCLUDE_DIRS "${system_DOC_STRING}" ${ARGN})
endmacro(remove_from_SYSTEM_INCLUDE_DIRS)
# Remove a string from C or CXX system defined macros.
# The string to be removed is passed as a regular expression within the optional the last argument
# If there is no regular expression, ALL system defined macros will be removed.
macro(remove_from_SYSTEM_MACROS LANGUAGE)
set(system_DOC_STRING "${LANGUAGE} compiler system defined macros")
remove_from_SYSTEM_ITEM(${LANGUAGE} _SYSTEM_DEFINED_MACROS "${system_DOC_STRING}" ${ARGN})
endmacro(remove_from_SYSTEM_MACROS)
if(NOT ${MESSAGE_TABS} STREQUAL "")
STRING(SUBSTRING ${MESSAGE_TABS} 1 -1 MESSAGE_TABS)
endif(NOT ${MESSAGE_TABS} STREQUAL "")
message("${MESSAGE_TABS}language_provider.cmake done.\n")
I hope that will help other people facing the same problem.
|
|
|
|
Powered by
FUDForum. Page generated in 0.03622 seconds