I was very excited to see that CMake 3.12rc1 now has support for linking
object libraries, making usage requirements propagate to top level targets
that use these libraries. However, I'm having trouble putting the concept
into practice to build a DLL on Windows 10 using Visual Studio 2017's
compiler (MSVC 19.x I think).

There's a minimal self-contained example here:

https://gitlab.com/detly/cmake-dll-ex

The point is to make a DLL of "module2" that exports the "module2()"
function. This is the "module2_dll" target in
modules/module2/CMakeLists.txt. If you don't want to pore over that
project, basically I have this structure:

  /
    - common
    - modules/
      - module1 (depends on "common")
      - module2 (depends on "common" and "module1", exports "module2()")

In common/CMakeLists.txt I have 'add_library(common OBJECT "common.c")'.
Similarly for module1 and module2, and module1 also has
'target_link_libraries(module1 PUBLIC common)' and module2 has
'target_link_libraries(module2 PUBLIC module1 common)'. (I am aware that
some build systems don't like build targets without source files, but
adding "module2.c" doesn't change things.)

Finally there's a DLL target:

add_library(module2_dll SHARED)
target_link_libraries(module2_dll module2)

I build this by doing:

    mkdir build
    cd build
    cmake ..
    cmake --build . --target module2_dll

The toolchain information shows:

-- Building for: Visual Studio 15 2017
-- The C compiler identification is MSVC 19.13.26129.0
-- The CXX compiler identification is MSVC 19.13.26129.0
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual
Studio/2017/Community/VC/Tools/MSVC/14.13.26128/bin/Hostx86/x86/cl.exe
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual
Studio/2017/Community/VC/Tools/MSVC/14.13.26128/bin/Hostx86/x86/cl.exe --
works

Now I would expect that building the module2_dll target would build .obj
files for all dependencies and link them all together as a DLL. But it
ultimately fails with:

"C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\module2_dll.vcxproj"
(default target) (1) ->
(Link target) ->
  module2.obj : error LNK2019: unresolved external symbol _common
referenced in function _module2 [C:\Users\heerij\Code
\cmake-dll-ex\build\modules\module2\module2_dll.vcxproj]
  module2.obj : error LNK2019: unresolved external symbol _module1
referenced in function _module2 [C:\Users\heerij\Cod
e\cmake-dll-ex\build\modules\module2\module2_dll.vcxproj]

C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\Debug\module2_dll.dll
: fatal error LNK1120: 2 unresolved ext ernals
[C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\module2_dll.vcxproj]

If I remove the "SHARED" option from 'add_library(module2_dll)', it builds
a .lib file just fine. If I build the module2 target (not module2_dll), it
builds a .lib file as well. But I want a DLL.

I was surprised to see two things:

1. The final link command only runs on module2.obj, not module1.obj or
common.obj. If I were doing it by hand I'd link all three as the final step.

2. The intermediate commands build both .obj and .lib files. Are the .lib
files required? I don't know enough about Windows build mechanics to know.

Example output for #1:

Link:
  C:\Program Files (x86)\Microsoft Visual
Studio\2017\Community\VC\Tools\MSVC\14.13.26128\bin\HostX86\x86\link.exe
/ERR
  ORREPORT:QUEUE
/OUT:"C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\Debug\module2_dll.dll"
/INCREMENTAL /NOL
  OGO 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 /DEBUG /PDB:"C:/Users/heerij/Code/cma
  ke-dll-ex/build/modules/module2/Debug/module2_dll.pdb" /SUBSYSTEM:CONSOLE
/TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"C:

/Users/heerij/Code/cmake-dll-ex/build/modules/module2/Debug/module2_dll.lib"
/MACHINE:X86 /SAFESEH  /machine:X86 /DLL

 
"C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\module2.dir\Debug\module2.obj"

Example output for #2:

ClCompile:
  C:\Program Files (x86)\Microsoft Visual
Studio\2017\Community\VC\Tools\MSVC\14.13.26128\bin\HostX86\x86\CL.exe /c
/I"
  C:\Users\heerij\Code\cmake-dll-ex\modules\module2"
/I"C:\Users\heerij\Code\cmake-dll-ex\common" /I"C:\Users\heerij\Co
  de\cmake-dll-ex\modules\module1" /Zi /nologo /W3 /WX-
/diagnostics:classic /Od /Ob0 /Oy- /D WIN32 /D _WINDOWS /D "CMA
  KE_INTDIR=\"Debug\"" /D _MBCS /Gm- /RTC1 /MDd /GS /fp:precise /Zc:wchar_t
/Zc:forScope /Zc:inline /Fo"module2.dir\Deb
  ug\\" /Fd"module2.dir\Debug\module2.pdb" /Gd /TC /analyze- /FC
/errorReport:queue "C:\Users\heerij\Code\cmake-dll-ex\
  modules\module2\module2.c"
  module2.c
Lib:
  C:\Program Files (x86)\Microsoft Visual
Studio\2017\Community\VC\Tools\MSVC\14.13.26128\bin\HostX86\x86\Lib.exe
/OUT:
  "module2.dir\Debug\module2.lib" /NOLOGO  /machine:X86
module2.dir\Debug\module2.obj

"C:\Users\heerij\Code\cmake-dll-ex\build\common\common.dir\Debug\common.obj"

"C:\Users\heerij\Code\cmake-dll-ex\build\modules\module1\module1.dir\Debug\module1.obj"
  module2.vcxproj ->
C:\Users\heerij\Code\cmake-dll-ex\build\modules\module2\module2.dir\Debug\module2.lib

I didn't want to dump the entire MSVC output here because there's a tonne
of it. But if you don't want to try this yourself, the output is here:

https://gitlab.com/snippets/1728169

Have I misunderstood how object library usage requirements and dependencies
propagate? I would appreciate any pointers on this.

- Jason Heeris
-- 

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

Reply via email to