CMake & GitHub Actions - Windows build of CMake library on GitHub Actions not linking library to test suite

Viewed 1598

I have an open source CMake project that runs perfectly well on Linux. However, to make it more portable, I decided to add in Windows build options. To test this, I set up the GitHub Actions CMake Based Applications, and set the conditions to build on ubuntu-latest, windows-latest, and macos-latest.

My workflow file is as follows:

name: CMake

on: [push]

env:
  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
  BUILD_TYPE: Release

jobs:
  build:
    # The CMake configure and build commands are platform agnostic and should work equally
    # well on Windows or Mac.  You can convert this to a matrix build if you need
    # cross-platform coverage.
    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]

    steps:
    - uses: actions/checkout@v2

    - name: Create Build Environment
      # Some projects don't allow in-source building, so create a separate build directory
      # We'll use this as our working directory for all subsequent commands
      run: cmake -E make_directory ${{github.workspace}}/build

    - name: Configure CMake
      # Use a bash shell so we can use the same syntax for environment variable
      # access regardless of the host operating system
      shell: bash
      working-directory: ${{github.workspace}}/build
      # Note the current convention is to use the -S and -B options here to specify source 
      # and build directories, but this is only available with CMake 3.13 and higher.  
      # The CMake binaries on the Github Actions machines are (as of this writing) 3.12
      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON

    - name: Build
      working-directory: ${{github.workspace}}/build
      shell: bash
      # Execute the build.  You can specify a specific target with "--target <NAME>"
      run: cmake --build . --config $BUILD_TYPE

    - name: Test
      working-directory: ${{github.workspace}}/build
      shell: bash
      # Execute tests defined by the CMake configuration.  
      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
      run: ctest -C $BUILD_TYPE

It's pretty standard and works fine. The problem arrives when I try to build on Windows, and only Windows. To add portability to Windows, I added this to my CMakeLists.txt:

if(WIN32)
    set(FETCHCONTENT_BASE_DIR "C:/Users/$ENV{USERNAME}/AppData/Local/Temp")
endif()

This worked perfectly to keep my fetched dependencies outside of the source directory (CMake would complain). But when I tried to build with Windows, the library would get built fine but couldn't be found to be linked with the testing suite (Catch2 + CTest).

Link:
  C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\bin\HostX64\x64\link.exe /ERRORREPORT:QUEUE /OUT:"D:\a\libeztp\libeztp\build\tests\Release\tests.exe" /INCREMENTAL:NO /NOLOGO ..\Release\libeztp.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"D:/a/libeztp/libeztp/build/tests/Release/tests.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"D:/a/libeztp/libeztp/build/tests/Release/tests.lib" /MACHINE:X64  /machine:x64 tests.dir\Release\mainTest.obj
LINK : fatal error LNK1181: cannot open input file '..\Release\libeztp.lib' [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]
Done Building Project "D:\a\libeztp\libeztp\build\tests\tests.vcxproj" (default targets) -- FAILED.
Done Building Project "D:\a\libeztp\libeztp\build\ALL_BUILD.vcxproj" (default targets) -- FAILED.

Build FAILED

...

D:\a\libeztp\libeztp\build\ALL_BUILD.vcxproj" (default target) (1) ->
"D:\a\libeztp\libeztp\build\tests\tests.vcxproj" (default target) (5) ->
(Link target) -> 
  LINK : fatal error LNK1181: cannot open input file '..\Release\libeztp.lib' [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]

I was pulling my hair out, and found this SO post that seemed to have a somewhat related problem. So to my CMakeLists.txt, I changed the Windows if to:

if(WIN32)
    set(FETCHCONTENT_BASE_DIR "C:/Users/$ENV{USERNAME}/AppData/Local/Temp")
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) # I did try commenting out this line, but it was the same error from before.
    set(BUILD_SHARED_LIBS TRUE)
endif()

Now the library was linking properly (or so it seems), but now it couldn't find some exported symbols.

Link:
  C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\bin\HostX64\x64\link.exe /ERRORREPORT:QUEUE /OUT:"D:\a\libeztp\libeztp\build\tests\Release\tests.exe" /INCREMENTAL:NO /NOLOGO ..\Release\libeztp.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"D:/a/libeztp/libeztp/build/tests/Release/tests.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"D:/a/libeztp/libeztp/build/tests/Release/tests.lib" /MACHINE:X64  /machine:x64 tests.dir\Release\mainTest.obj
mainTest.obj : error LNK2019: unresolved external symbol "class std::map<int,class eztp::Die,struct std::less<int>,class std::allocator<struct std::pair<int const ,class eztp::Die> > > eztp::dice" (?dice@eztp@@3V?$map@HVDie@eztp@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHVDie@eztp@@@std@@@4@@std@@A) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____0(void)" (?____C_A_T_C_H____T_E_S_T____0@@YAXXZ) [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]
D:\a\libeztp\libeztp\build\tests\Release\tests.exe : fatal error LNK1120: 1 unresolved externals [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]
Done Building Project "D:\a\libeztp\libeztp\build\tests\tests.vcxproj" (default targets) -- FAILED.
Done Building Project "D:\a\libeztp\libeztp\build\ALL_BUILD.vcxproj" (default targets) -- FAILED.

...

"D:\a\libeztp\libeztp\build\ALL_BUILD.vcxproj" (default target) (1) ->
"D:\a\libeztp\libeztp\build\tests\tests.vcxproj" (default target) (5) ->
(Link target) -> 
  mainTest.obj : error LNK2019: unresolved external symbol "class std::map<int,class eztp::Die,struct std::less<int>,class std::allocator<struct std::pair<int const ,class eztp::Die> > > eztp::dice" (?dice@eztp@@3V?$map@HVDie@eztp@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHVDie@eztp@@@std@@@4@@std@@A) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____0(void)" (?____C_A_T_C_H____T_E_S_T____0@@YAXXZ) [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]
  D:\a\libeztp\libeztp\build\tests\Release\tests.exe : fatal error LNK1120: 1 unresolved externals [D:\a\libeztp\libeztp\build\tests\tests.vcxproj]

At this point, I'm exhausted and just want this to be over, as I haven't plan on developing on Windows for quite some time. Could someone point me in the right direction and help me figure out what I'm missing? I'm just throwing stuff at a wall at this point and hoping something sticks.


Edit:

Here is the implementation of the exported symbol:

dice.hpp

namespace eztp {
    class Die {
        //Implementation probably irrelevant
    };

    extern std::map<int, Die> dice;
}

dice.cpp

std::map<int, eztp::Die> eztp::dice = {
        {0,   eztp::Die(0)},
        {1,   eztp::Die(1)},
        {2,   eztp::Die(2)},
        {4,   eztp::Die(4)},
        {6,   eztp::Die(6)},
        {8,   eztp::Die(8)},
        {10,  eztp::Die(10)},
        {12,  eztp::Die(12)},
        {20,  eztp::Die(20)},
        {100, eztp::Die(100)}
};
0 Answers
Related