ETLCPP / etl

Embedded Template Library
https://www.etlcpp.com
MIT License
2.05k stars 372 forks source link

Unresolved External Symbols When Disabling STL #846

Closed pinwhell closed 4 months ago

pinwhell commented 4 months ago

When disabling STL in MSVC, I've found that vector compiles fine, but unordered_map fails to compile due to dependencies on other parts of the STL. I've tried including the profile header, manually adding the NO_STL flag, and even placing the necessary headers in the STL include folder, but none of these approaches have resolved the issue. Any insights or suggestions would be greatly appreciated.

cmake_minimum_required(VERSION 3.20)

set(CMAKE_PREFIX_PATH "C:/Program Files (x86)")

find_package(etl REQUIRED)

project (TestETL)

if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
    # For MSVC compiler
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zl")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:main")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    # For GCC and Clang
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -nostdlib")
endif()

add_executable(${PROJECT_NAME} main.cpp)

add_compile_definitions(ETL_NO_STL)

target_link_libraries(${PROJECT_NAME} etl::etl)
#include <etl/vector.h>
#include <etl/unordered_map.h>

extern "C" int main()
{
    etl::vector<int, 20> test;
    etl::unordered_map<int, int, 200> test2;

    //test2[10] = 20;

    test.push_back(250);

    return test[0] /*+ test2[10]*/;
}

It will generate this errors:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol "void __stdcall `eh vector constructor iterator'(void *,unsigned int,unsigned int,void (__thiscall*)(void *),void (__thiscall*)(void *))" (??_L@YGXPAXIIP6EX0@Z1@Z) referenced in function "public: __thiscall etl::unordered_map<int,int,200,200,struct etl::hash<int>,struct etl::equal_to<int> >::unordered_map<int,int,200,200,struct etl::hash<int>,struct etl::equal_to<int> >(struct etl::hash<int> const &,struct etl::equal_to<int> const &)" (??0?$unordered_map@HH$0MI@$0MI@U?$hash@H@etl@@U?$equal_to@H@2@@etl@@QAE@ABU?$hash@H@1@ABU?$equal_to@H@1@@Z)  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\main.cpp.obj 1   
Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol "void __stdcall `eh vector destructor iterator'(void *,unsigned int,unsigned int,void (__thiscall*)(void *))" (??_M@YGXPAXIIP6EX0@Z@Z) referenced in function "public: __thiscall etl::unordered_map<int,int,200,200,struct etl::hash<int>,struct etl::equal_to<int> >::~unordered_map<int,int,200,200,struct etl::hash<int>,struct etl::equal_to<int> >(void)" (??1?$unordered_map@HH$0MI@$0MI@U?$hash@H@etl@@U?$equal_to@H@2@@etl@@QAE@XZ) C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\main.cpp.obj 1   
Severity    Code    Description Project File    Line    Suppression State
Error   LNK2001 unresolved external symbol ___std_terminate C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\main.cpp.obj 1
Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol ___CxxFrameHandler3 referenced in function __ehhandler$??1?$unordered_map@HH$0MI@$0MI@U?$hash@H@etl@@U?$equal_to@H@2@@etl@@QAE@XZ    C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\main.cpp.obj 1   
Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol __chkstk referenced in function _main    C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\main.cpp.obj 1
Severity    Code    Description Project File    Line    Suppression State
Error   LNK2001 unresolved external symbol __load_config_used   C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\TestETL  C:\Users\_\Documents\C++\TestETL\out\build\x86-Release\LINK 1   
jwellbelove commented 4 months ago

It compiles OK for me as a VS2022 project. I'm not a CMake expert, but I'll try to see if I can replicate the issue.

jwellbelove commented 4 months ago

I get errors with find_package(etl REQUIRED).

pinwhell commented 4 months ago

@jwellbelove make sure to install ETL first on a place like Program Files x86, then set that base path where you installed it, in my case

set(CMAKE_PREFIX_PATH "C:/Program Files (x86)")

if you want to simply go with Visual Studio Directly, then simply make sure to disable Run-Time Library CRT, maybe disable conflicting symbols like stack coockies functions(related to the CRT), and make sure to ensure your program starting at main instead of CRT default one, that should replicate the problem

jwellbelove commented 4 months ago
cmake_minimum_required(VERSION 3.20)

# Path to the ETL library
set(CMAKE_PREFIX_PATH "D:/Users/John/Programming/GitHub/etl")

find_package(etl REQUIRED)

project(TestETL)

if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
    # For MSVC compiler
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zl")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:main")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    # For GCC and Clang
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -nostdlib")
endif()

add_executable(${PROJECT_NAME} main.cpp)

add_compile_definitions(ETL_NO_STL)

target_link_libraries(${PROJECT_NAME} etl::etl)
1> [CMake] CMake Error at D:\Users\John\Programming\Experiments\Issue-846\CMakeLists.txt:5 (find_package):
1> [CMake]   By not providing "Findetl.cmake" in CMAKE_MODULE_PATH this project has
1> [CMake]   asked CMake to find a package configuration file provided by "etl", but
1> [CMake]   CMake did not find one.
1> [CMake] 
1> [CMake]   Could not find a package configuration file provided by "etl" with any of
1> [CMake]   the following names:
1> [CMake] 
1> [CMake]     etlConfig.cmake
1> [CMake]     etl-config.cmake
1> [CMake] 
1> [CMake]   Add the installation prefix of "etl" to CMAKE_PREFIX_PATH or set "etl_DIR"
1> [CMake]   to a directory containing one of the above files.  If "etl" provides a
1> [CMake]   separate development package or SDK, be sure it has been installed.
1> [CMake] 
1> [CMake] 
1> [CMake] -- Configuring incomplete, errors occurred!
jwellbelove commented 4 months ago

This works for me.

cmake_minimum_required(VERSION 3.20)

project(TestETL)

if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
    # For MSVC compiler
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS-")
    #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zl")
    #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:main")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    # For GCC and Clang
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -nostdlib")
endif()

add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE "D:/Users/John/Programming/GitHub/etl/include")
add_compile_definitions(ETL_NO_STL)
jwellbelove commented 4 months ago

If I use this CMakelists.txt and use an empty main() I still get this.

cmake_minimum_required(VERSION 3.20)

project(TestETL)

if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
    # For MSVC compiler
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
    string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GS-")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zl")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:main")
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    # For GCC and Clang
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -nostdlib")
endif()

add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE "D:/Users/John/Programming/GitHub/etl/include")
add_compile_definitions(ETL_NO_STL)
extern "C" int main()
{
}
FAILED: TestETL.exe 

D:\Users\John\Programming\Experiments\Issue-846\out\build\x64-Debug\main.cpp.obj : error LNK2001: unresolved external symbol _RTC_InitBase

D:\Users\John\Programming\Experiments\Issue-846\out\build\x64-Debug\main.cpp.obj : error LNK2001: unresolved external symbol _RTC_Shutdown

D:\Users\John\Programming\Experiments\Issue-846\out\build\x64-Debug\TestETL.exe : fatal error LNK1120: 2 unresolved externals

  ninja: build stopped: subcommand failed.

Build All failed.
jwellbelove commented 4 months ago

The ETL uses some C library functions.

pinwhell commented 4 months ago

what could be a posible way around it? maybe reverse engineer those c funcs and replicate them into ETL?

jwellbelove commented 4 months ago

The problem with the minimal VS solution is that it seems to want to call _RTC_InitBase and _RTC_Shutdown anyway.

pinwhell commented 4 months ago

I see. In my case, I didn't encounter the exact problems you're facing. Mine were somewhat similar but a bit different. They were related to the CRTStartup() symbol not being found, but simply repointing to main() as startup with a linker parameter was enough to fix it. However, after overcoming those issues, I encountered the unresolved link problems mentioned earlier. I've since resolved them and identified the root cause. Surprisingly, it wasn't caused by the ETL itself as initially thought. The ETL was indeed invoking exception handling stuff, but it appeared to be default behavior from the compiler rather than an intentional call. Those symbols were coming from the STL. Disabling exception handling and exceptions themselves resolved it. Later, I faced additional linking problems related to stack protection and stack probing. Again, the solution was straightforward: disabling stack protection and stack probing. However, it's important to note that this could potentially expose vulnerabilities. Such challenges seem to be the default trade-off when working without the STL.

jwellbelove commented 4 months ago

Glad you got to the root of the issue.