fmt 7.0.0 + shared + Visual Studio : Undefined References

Created on 7 Jul 2020  路  3Comments  路  Source: fmtlib/fmt

(maybe same issue than https://github.com/fmtlib/fmt/issues/1753, but different compiler)

Since 7.0.0, these two simple test programs fail to link when fmt is built as a shared lib with Visual Studio (2017 and 2019, maybe others versions). It works if fmt is header only or static.

CMakeLists.txt:

cmake_minimum_required(VERSION 3.1.2)
project(test_package CXX)

find_package(fmt REQUIRED CONFIG)

# TEST_PACKAGE #################################################################
add_executable(${CMAKE_PROJECT_NAME} test_package.cpp)
set_property(TARGET ${CMAKE_PROJECT_NAME} PROPERTY CXX_STANDARD 14)
if(FMT_HEADER_ONLY)
    target_link_libraries(${CMAKE_PROJECT_NAME} fmt::fmt-header-only)
else()
    target_link_libraries(${CMAKE_PROJECT_NAME} fmt::fmt)
endif()

# TEST_RANGES ##################################################################
add_executable(test_ranges test_ranges.cpp)
set_property(TARGET test_ranges PROPERTY CXX_STANDARD 14)
if(FMT_HEADER_ONLY)
    target_link_libraries(test_ranges fmt::fmt-header-only)
else()
    target_link_libraries(test_ranges fmt::fmt)
endif()

test_package.cpp:

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <limits>


#include "fmt/format.h"
#include "fmt/printf.h"
#include "fmt/ostream.h"
#include "fmt/color.h"


void vreport(const char *format, fmt::format_args args) {
    fmt::vprint(format, args);
}

template <typename... Args>
void report(const char *format, const Args & ... args) {
    vreport(format, fmt::make_format_args(args...));
}

class Date {
    int year_, month_, day_;
  public:
    Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}

    friend std::ostream &operator<<(std::ostream &os, const Date &d) {
        return os << d.year_ << '-' << d.month_ << '-' << d.day_;
    }
};

int main() {
    const std::string thing("World");
    fmt::print("PRINT: Hello {}!\n", thing);
    fmt::printf("PRINTF: Hello, %s!\n", thing);

    const std::string formatted = fmt::format("{0}{1}{0}", "abra", "cad");
    fmt::print("{}\n", formatted);

    fmt::memory_buffer buf;
    fmt::format_to(buf, "{}", 2.7182818);
    fmt::print("Euler number: {}\n", fmt::to_string(buf));

    const std::string date = fmt::format("The date is {}\n", Date(2012, 12, 9));
    fmt::print(date);

    report("{} {} {}\n", "Conan", 42, 3.14159);

    fmt::print(std::cout, "{} {}\n", "Magic number", 42);

    fmt::print(fg(fmt::color::aqua), "Bincrafters\n");

    return EXIT_SUCCESS;
}

test_ranges.cpp:

#include <cstdlib>
#include <vector>
#include "fmt/ranges.h"

int main() {
    std::vector<char> numbers;
    fmt::format_to(std::back_inserter(numbers), "{}{}{}", 1, 2, 3);
    const std::string str_numbers = fmt::format("{}", numbers);
    fmt::print("numbers: {}\n", str_numbers);
    return EXIT_SUCCESS;
}

Errors:

test_package.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fmt::v6::detail::vformat(class fmt::v6::basic_string_view<char>,struct fmt::v6::format_args)" (?vformat@detail@v6@fmt@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$basic_string_view@D@23@Uformat_args@23@@Z) referenced in function main
test_ranges.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl fmt::v6::detail::vformat(class fmt::v6::basic_string_view<char>,struct fmt::v6::format_args)" (?vformat@detail@v6@fmt@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$basic_string_view@D@23@Uformat_args@23@@Z) referenced in function main

Might be related to modifications made into core.h for FMT_EXTERN_TEMPLATE_API ? AFAIK, for Visual Studio (but not others compiler on Windows) FMT_EXTERN_TEMPLATE_API shouldn't be __declspec(dllexport) at build time, only FMT_INSTANTIATION_DEF_API.
Seems like also that changes made to FMT_EXTERN_TEMPLATE_API now prevent to build fmt with fvisibility hidden for GNU compilers.

EDIT:
explicit instantiation definition of std::string internal::vformat<char>(string_view, basic_format_args<format_context>) has been removed from format.cc in 7.0.0. Therefore it has no chance to be exported I guess.

Most helpful comment

Yes it works, thanks @Kurkin

All 3 comments

Does #1757 fix the error?

Yes it works, thanks @Kurkin

Was this page helpful?
0 / 5 - 0 ratings