Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For non-SPDLOG_HEADER_ONLY builds enable export attributes for symbols #3146

Open
tomilov opened this issue Jul 26, 2024 · 9 comments
Open

Comments

@tomilov
Copy link

tomilov commented Jul 26, 2024

Currently, when spdlog used with -DSPDLOG_BUILD_SHARED=ON and project has (project-wide) setting set(CMAKE_CXX_VISIBILITY_PRESET hidden), interface symbols are not exported from libspdlogd.so/libspdlog.so. Platform: Linux, g++/clang++. Project uses spdlog as git submodule.

CMake has ultimate GenerateExportHeader functionality, which can be used to manage related stuff easely.

@tt4g
Copy link
Contributor

tt4g commented Jul 26, 2024

PR is welcome.

@tt4g
Copy link
Contributor

tt4g commented Jul 26, 2024

This proposal was previously closed (#1257).

@tomilov
Copy link
Author

tomilov commented Jul 30, 2024

This proposal was previously closed (#1257).

I see. I think that work should not be wasted.

@tomilov
Copy link
Author

tomilov commented Jul 30, 2024

Currently either all symbols exported from every dll (so) uses the library, or there are linking errors. What if I link against two shared libraries compiled with two different versions of the spdlog? I suspect it will be a problem in current state.

@tt4g
Copy link
Contributor

tt4g commented Jul 30, 2024

If the spdlog library is not exporting symbols, wouldn't your application not be able to find the symbols that spdlog was exporting when linking, resulting in a link error?

@tomilov
Copy link
Author

tomilov commented Jul 30, 2024

This is true.
If I make default visibility hidden for the whole project (including external submodules, like spdlog), I get link errors, because spdlog not exporting at all.
If I don't make default visibility hidden (but default) for external submodules and spdlog is static then any my dll (so), that uses spdlog (effectively means "all dlls") exports these symbols:

nm -gDC --defined-only lib*.so | awk 'match($2, /D|T/) { print substr($0, index($0, $3)) }' | grep spdlog spdlog::should_log(spdlog::level::level_enum) spdlog::set_pattern(std::__cxx11::basic_string, std::allocator >, spdlog::pattern_time_type) spdlog::async_logger::backend_flush_() spdlog::async_logger::backend_sink_it_(spdlog::details::log_msg const&) spdlog::async_logger::clone(std::__cxx11::basic_string, std::allocator >) spdlog::async_logger::flush_() spdlog::async_logger::sink_it_(spdlog::details::log_msg const&) spdlog::async_logger::async_logger(std::__cxx11::basic_string, std::allocator >, std::shared_ptr, std::weak_ptr, spdlog::async_overflow_policy) spdlog::async_logger::async_logger(std::__cxx11::basic_string, std::allocator >, std::initializer_list >, std::weak_ptr, spdlog::async_overflow_policy) spdlog::async_logger::async_logger(std::__cxx11::basic_string, std::allocator >, std::shared_ptr, std::weak_ptr, spdlog::async_overflow_policy) spdlog::async_logger::async_logger(std::__cxx11::basic_string, std::allocator >, std::initializer_list >, std::weak_ptr, spdlog::async_overflow_policy) spdlog::set_formatter(std::unique_ptr >) spdlog::default_logger() spdlog::dump_backtrace() spdlog::register_logger(std::shared_ptr) spdlog::throw_spdlog_ex(std::__cxx11::basic_string, std::allocator >) spdlog::throw_spdlog_ex(std::__cxx11::basic_string, std::allocator > const&, int) spdlog::enable_backtrace(unsigned long) spdlog::disable_backtrace() spdlog::initialize_logger(std::shared_ptr) spdlog::pattern_formatter::set_pattern(std::__cxx11::basic_string, std::allocator >) spdlog::pattern_formatter::need_localtime(bool) spdlog::pattern_formatter::handle_padspec_(__gnu_cxx::__normal_iterator, std::allocator > >&, __gnu_cxx::__normal_iterator, std::allocator > >) spdlog::pattern_formatter::compile_pattern_(std::__cxx11::basic_string, std::allocator > const&) spdlog::pattern_formatter::format(spdlog::details::log_msg const&, fmt::v10::basic_memory_buffer >&) spdlog::pattern_formatter::get_time_(spdlog::details::log_msg const&) spdlog::pattern_formatter::pattern_formatter(spdlog::pattern_time_type, std::__cxx11::basic_string, std::allocator >) spdlog::pattern_formatter::pattern_formatter(std::__cxx11::basic_string, std::allocator >, spdlog::pattern_time_type, std::__cxx11::basic_string, std::allocator >, std::unordered_map >, std::hash, std::equal_to, std::allocator > > > >) spdlog::pattern_formatter::pattern_formatter(spdlog::pattern_time_type, std::__cxx11::basic_string, std::allocator >) spdlog::pattern_formatter::pattern_formatter(std::__cxx11::basic_string, std::allocator >, spdlog::pattern_time_type, std::__cxx11::basic_string, std::allocator >, std::unordered_map >, std::hash, std::equal_to, std::allocator > > > >) spdlog::set_error_handler(void (*)(std::__cxx11::basic_string, std::allocator > const&)) spdlog::default_logger_raw() spdlog::set_default_logger(std::shared_ptr) spdlog::apply_logger_env_levels(std::shared_ptr) spdlog::set_automatic_registration(bool) spdlog::get(std::__cxx11::basic_string, std::allocator > const&) spdlog::drop(std::__cxx11::basic_string, std::allocator > const&) spdlog::swap(spdlog::logger&, spdlog::logger&) spdlog::level::to_short_c_str(spdlog::level::level_enum) spdlog::level::to_string_view(spdlog::level::level_enum) spdlog::level::from_str(std::__cxx11::basic_string, std::allocator > const&) spdlog::sinks::sink::set_level(spdlog::level::level_enum) spdlog::logger::set_pattern(std::__cxx11::basic_string, std::allocator >, spdlog::pattern_time_type) spdlog::logger::err_handler_(std::__cxx11::basic_string, std::allocator > const&) spdlog::logger::set_formatter(std::unique_ptr >) spdlog::logger::should_flush_(spdlog::details::log_msg const&) spdlog::logger::dump_backtrace() spdlog::logger::dump_backtrace_() spdlog::logger::enable_backtrace(unsigned long) spdlog::logger::disable_backtrace() spdlog::logger::set_error_handler(std::function, std::allocator > const&)>) spdlog::logger::swap(spdlog::logger&) spdlog::logger::clone(std::__cxx11::basic_string, std::allocator >) spdlog::logger::flush() spdlog::logger::sinks() spdlog::logger::flush_() spdlog::logger::log_it_(spdlog::details::log_msg const&, bool, bool) spdlog::logger::flush_on(spdlog::level::level_enum) spdlog::logger::sink_it_(spdlog::details::log_msg const&) spdlog::logger::set_level(spdlog::level::level_enum) spdlog::logger::operator=(spdlog::logger) spdlog::logger::logger(spdlog::logger&&) spdlog::logger::logger(spdlog::logger const&) spdlog::logger::logger(spdlog::logger&&) spdlog::logger::logger(spdlog::logger const&) spdlog::details::backtracer::foreach_pop(std::function) spdlog::details::backtracer::enable(unsigned long) spdlog::details::backtracer::disable() spdlog::details::backtracer::push_back(spdlog::details::log_msg const&) spdlog::details::backtracer::operator=(spdlog::details::backtracer) spdlog::details::backtracer::backtracer(spdlog::details::backtracer&&) spdlog::details::backtracer::backtracer(spdlog::details::backtracer const&) spdlog::details::backtracer::backtracer(spdlog::details::backtracer&&) spdlog::details::backtracer::backtracer(spdlog::details::backtracer const&) spdlog::details::thread_pool::post_flush(std::shared_ptr&&, spdlog::async_overflow_policy) spdlog::details::thread_pool::queue_size() spdlog::details::thread_pool::worker_loop_() spdlog::details::thread_pool::discard_counter() spdlog::details::thread_pool::overrun_counter() spdlog::details::thread_pool::post_async_msg_(spdlog::details::async_msg&&, spdlog::async_overflow_policy) spdlog::details::thread_pool::process_next_msg_() spdlog::details::thread_pool::reset_discard_counter() spdlog::details::thread_pool::reset_overrun_counter() spdlog::details::thread_pool::post_log(std::shared_ptr&&, spdlog::details::log_msg const&, spdlog::async_overflow_policy) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long, std::function) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long, std::function, std::function) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long, std::function) spdlog::details::thread_pool::thread_pool(unsigned long, unsigned long, std::function, std::function) spdlog::details::thread_pool::~thread_pool() spdlog::details::thread_pool::~thread_pool() spdlog::details::log_msg_buffer::update_string_views() spdlog::details::log_msg_buffer::operator=(spdlog::details::log_msg_buffer&&) spdlog::details::log_msg_buffer::operator=(spdlog::details::log_msg_buffer const&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg_buffer&&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg const&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg_buffer const&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg_buffer&&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg const&) spdlog::details::log_msg_buffer::log_msg_buffer(spdlog::details::log_msg_buffer const&) spdlog::details::periodic_worker::~periodic_worker() spdlog::details::periodic_worker::~periodic_worker() spdlog::details::os::create_dir(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::_thread_id() spdlog::details::os::in_terminal(_IO_FILE*) spdlog::details::os::path_exists(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::filename_to_str(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::remove_if_exists(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::sleep_for_millis(unsigned int) spdlog::details::os::is_color_terminal() spdlog::details::os::utc_minutes_offset(tm const&) spdlog::details::os::now() spdlog::details::os::pid() spdlog::details::os::fsync(_IO_FILE*) spdlog::details::os::getenv[abi:cxx11](char const*) spdlog::details::os::gmtime(long const&) spdlog::details::os::gmtime() spdlog::details::os::remove(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::rename(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::fopen_s(_IO_FILE**, std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::dir_name(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::os::filesize(_IO_FILE*) spdlog::details::os::localtime(long const&) spdlog::details::os::localtime() spdlog::details::os::thread_id() spdlog::details::log_msg::log_msg(fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::log_msg::log_msg(std::chrono::time_point > >, spdlog::source_loc, fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::log_msg::log_msg(fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::log_msg::log_msg(std::chrono::time_point > >, spdlog::source_loc, fmt::v10::basic_string_view, spdlog::level::level_enum, fmt::v10::basic_string_view) spdlog::details::registry::set_levels(std::unordered_map, std::allocator >, spdlog::level::level_enum, std::hash, std::allocator > >, std::equal_to, std::allocator > >, std::allocator, std::allocator > const, spdlog::level::level_enum> > >, spdlog::level::level_enum*) spdlog::details::registry::set_formatter(std::unique_ptr >) spdlog::details::registry::default_logger() spdlog::details::registry::get_default_raw() spdlog::details::registry::register_logger(std::shared_ptr) spdlog::details::registry::enable_backtrace(unsigned long) spdlog::details::registry::register_logger_(std::shared_ptr) spdlog::details::registry::throw_if_exists_(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::registry::disable_backtrace() spdlog::details::registry::initialize_logger(std::shared_ptr) spdlog::details::registry::set_error_handler(std::function, std::allocator > const&)>) spdlog::details::registry::set_default_logger(std::shared_ptr) spdlog::details::registry::apply_logger_env_levels(std::shared_ptr) spdlog::details::registry::set_automatic_registration(bool) spdlog::details::registry::get(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::registry::drop(std::__cxx11::basic_string, std::allocator > const&) spdlog::details::registry::get_tp() spdlog::details::registry::set_tp(std::shared_ptr) spdlog::details::registry::drop_all() spdlog::details::registry::flush_on(spdlog::level::level_enum) spdlog::details::registry::instance() spdlog::details::registry::shutdown() spdlog::details::registry::tp_mutex() spdlog::details::registry::apply_all(std::function)> const&) spdlog::details::registry::flush_all() spdlog::details::registry::set_level(spdlog::level::level_enum) spdlog::details::registry::registry() spdlog::details::registry::registry() spdlog::details::registry::~registry() spdlog::details::registry::~registry() spdlog::drop_all() spdlog::flush_on(spdlog::level::level_enum) spdlog::shutdown() spdlog::apply_all(std::function)> const&) spdlog::get_level() spdlog::set_level(spdlog::level::level_enum) spdlog::spdlog_ex::spdlog_ex(std::__cxx11::basic_string, std::allocator >) spdlog::spdlog_ex::spdlog_ex(std::__cxx11::basic_string, std::allocator > const&, int) spdlog::spdlog_ex::spdlog_ex(std::__cxx11::basic_string, std::allocator >) spdlog::spdlog_ex::spdlog_ex(std::__cxx11::basic_string, std::allocator > const&, int)
But my libraries should not export anything, except explicitly marked for export (by mentioned CMake's mechanism), especially symbols of spdlog.

@tt4g
Copy link
Contributor

tt4g commented Jul 30, 2024

-fvisibility=hidden option is intended to simplify the task of exporting only some public APIs from the library, and some public API symbols will still cause conflicts at link time.
Since linkers usually link with the first symbol found, libraries linked with different versions of spdlog will cause link errors at link time or undefined behavior at runtime.

Since your problem is caused by using different versions of spdlog, you should rebuild all your libraries using the same version of spdlog.

@tomilov
Copy link
Author

tomilov commented Aug 3, 2024

Exactly. If default visibility is hidden. If default visibility is "default" and I use spdlog, all my *.so files exports spdlog's symbols.

@tt4g
Copy link
Contributor

tt4g commented Aug 3, 2024

Even if supporting CMAKE_CXX_VISIBILITY_PRESET, the symbols of the public API must be exposed.
It would not solve the problem of libraries using different versions of spdlog.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants