Search code examples
c++visual-studiolinkerzlib

Unresolved external symbol for statically build zlib


I'm on VS2022. I'm creating a little static library to handle embedded resources (so let's call it er) in my c++ project.

This library uses zlib (latest version, 1.3.1) to compress the files before processing it (details don't really matter here). So I built zlib and linked my er project against zlibstaticd.lib and zlibstatic.lib.

The cmake file is something like:

set (EXPORT_HEADER_FILES
    export/er/er.hpp
)
set (SOURCE_FILES
    cpp/er.cpp
)

source_group("er/cpp" FILES ${SOURCE_FILES})
source_group("er/export" FILES ${EXPORT_HEADER_FILES})

add_library(er STATIC ${EXPORT_HEADER_FILES} ${SOURCE_FILES})

set(ZLIB_LIBS 
    debug ${ZLIB_LIBRARY}/zlibstaticd.lib optimized ${ZLIB_LIBRARY}/zlibstatic.lib
)

target_link_libraries(er PRIVATE ${ZLIB_LIBS})

target_include_directories(er
    PRIVATE hpp ${ZLIB_INCLUDE_DIRS}
    PUBLIC export
)

Everything's fine so far.

Now, the point is I want er to be standalone, that's why zlib is linked privately. There is no mention of zlib in the er.hpp file.

So now I build er, and want to use it in my other project (lib2 let's call it).

So I add er and link it as static lib to my project (just like I did with zlib for er). But when I try to compile I now get linkers errors as follows:

Error   LNK2019 unresolved external symbol inflate referenced in function "bool __cdecl er::decompress(...)
Error   LNK2019 unresolved external symbol deflate referenced in function "bool __cdecl er::compress(...)
Error   LNK2019 unresolved external symbol deflateEnd referenced in function "bool __cdecl er::compress(...)
Error   LNK2019 unresolved external symbol inflateEnd referenced in function "bool __cdecl er::decompress(...)
Error   LNK2019 unresolved external symbol deflateInit_ referenced in function "bool __cdecl er::compress(...)
Error   LNK2019 unresolved external symbol inflateInit_ referenced in function "bool __cdecl er::decompress(...)

Now why would I get that? inflate, deflate, deflateEnd, inflateEnd,... Those are zlib functions and as I don't want to link zlib to lib2.

I'm really lost here. I tried the

#define ZLIB_WINAPI
#include <zlib/zlib.h>

in the er.cpp file like some can mentions in some answers I found on SO, but it doesn't do anything.


Solution

  • that's why zlib is linked privately.

    As Some programmer dude commented, archive libraries are not linked in any sense of the word.

    You can think of them as a shopping bag filled with object files. You want to prepare a baked potato with sour cream; you have potatoes in one shopping bag (er.lib) and sour cream in another (zlib.lib). When preparing the meal, you need to use both bags (at link time), i.e. link your final program with both er.lib and zlib.lib.

    You could put all of your ingredients into a single shopping bag, and then you would only need that one shopping bag (the combined erz.lib) at link time.

    To do that, you can unpack er.lib and zlib.lib to extract all the .obj files from them, and add these object files into the combined erz.lib library.

    Update:

    is there an automatic way to do it? I mean like a build rule or a cmake function?

    I don't know about cmake function, but you can trivially construct a Makefile rule for it. It turns out that (unlike UNIX ar) LIB.EXE can directly combine .LIB files in a single command:

    LIB.EXE /OUT:erz.lib er.lib zlib.lib