Symbols from Convenience Library Not Getting Exported in Executable

Symbols from convenience library not getting exported in executable

I managed to solve it. It was this note from John Calcote's excellent Autotools book that pointed me in the right direction:

Linkers add to the binary product every object file specified explicitly on the command line, but they only extract from archives those object files that are actually referenced in the code being linked.

To counteract this behavior, one can use the --whole-archive flag to libtool. However, this causes all the symbols from all the system libraries to be pulled in also, causing lots of double symbol definition errors. So --whole-archive needs to be right before libconvenience.a on the linker command line, and it needs to be followed by --no-whole-archive so that the other libraries aren't treated that way. This is a bit difficult since automake and libtool don't really guarantee keeping your flags in the same order on the command line, but this line in Makefile.am did the trick:

myprogram_LDFLAGS = -Wl,--export-dynamic \
-Wl,--whole-archive,libconvenience/libconvenience.a,--no-whole-archive

Executable exporting symbols BUT not getting exported as they are unreferenced by the executable itself

Problem: On windows, STATIC LIB which contains an OBJ file that has a function marked __decl-spec(dll¬export) but if the same is not used in the EXE, function does not get exported from the EXE. On other platforms also we have the same problem BUT there we have compiler options like --whole-archive / -force_load, do make it work.

Links:
Link1
Link2

Only solution that come to my mind is to not create STATIC libs, rather include all code (static LIBS) in the executable then:
1. It works on Windows
2. It works on Linux without --whole-archive
3. It works on Mac OS X without -force_load
4. We also need not worry about if 2 & 3 include the dead code, exe bloat etc.

This is the only solution till the linkers become smart and throw out every unused symbol, except those marked specifically for external consumption i.e. marked to be exported.

Symbols in C++ – are they exported in non-debug build?


a. stripped build

b. non-shared library build

It's not clear whether you are asking about a build that satisfies both A) and B), or the A) and B) scenarios separately.

For both -- non-shared, stripped build -- yes, the symbols should be all gone.

For just A), no: if you are using shared library, the symbols will be (by default) exported from it, and strip will not remove them. If you are using ELF, you could limit symbol visibility with e.g. __attribute__((visibility("hidden"))) or an equivalent mechanism.

For just B) -- non-stripped, non-shared build, the symbols will generally be present in the symbol table, and so strings will show them. To get rid of them, use strip (which turns this into A) and B) combined).

Some exported symbols disappear after creating a dynamic framework with the ios_framework rule

Can you try adding alwayslink = 1 to the objc_library target containing the C++ symbols? The linker is deadstripping the C++ symbols as they are not being referenced anywhere in the binary.

Export all symbols when creating a DLL


Short answer

You can do it with help of the new version of the CMake (any version cmake-3.3.20150721-g9cd2f-win32-x86.exe or higher).

Currently it's in the dev branch.
Later, the feature will be added in the release version of the cmake-3.4.

Link to the cmake dev:

cmake_dev

Link to an article which describe the technic:

Create dlls on Windows without declspec() using new CMake export all feature

Link to an example project:

cmake_windows_export_all_symbols


Long answer

Caution:
All information below is related to the MSVC compiler or Visual Studio.

If you use other compilers like gcc on Linux or MinGW gcc compiler on Windows you don't have linking errors due to not exported symbols, because gcc compiler export all symbols in a dynamic library (dll) by default instead of MSVC or Intel windows compilers.

In windows you have to explicitly export symbol from a dll.

More info about this is provided by links:

Exporting from a DLL

HowTo: Export C++ classes from a DLL

So if you want to export all symbols from dll with MSVC (Visual Studio compiler) you have two options:

  • Use the keyword __declspec(dllexport) in the class/function's definition.
  • Create a module definition (.def) file and use the .def file when building the DLL.

1. Use the keyword __declspec(dllexport) in the class/function's definition


1.1. Add "__declspec(dllexport) / __declspec(dllimport)" macros to a class or method you want to use. So if you want to export all classes you should add this macros to all of them

More info about this is provided by link:

Exporting from a DLL Using __declspec(dllexport)

Example of usage (replace "Project" by real project name):

// ProjectExport.h

#ifndef __PROJECT_EXPORT_H
#define __PROJECT_EXPORT_H

#ifdef USEPROJECTLIBRARY
#ifdef PROJECTLIBRARY_EXPORTS
#define PROJECTAPI __declspec(dllexport)
#else
#define PROJECTAPI __declspec(dllimport)
#endif
#else
#define PROJECTAPI
#endif

#endif

Then add "PROJECTAPI" to all classes.
Define "USEPROJECTLIBRARY" only if you want export/import symbols from dll.
Define "PROJECTLIBRARY_EXPORTS" for the dll.

Example of class export:

#include "ProjectExport.h"

namespace hello {
class PROJECTAPI Hello {}
}

Example of function export:

#include "ProjectExport.h"

PROJECTAPI void HelloWorld();

Caution: don't forget to include "ProjectExport.h" file.


1.2. Export as C functions.
If you use C++ compiler for compilation code is written on C, you could add extern "C" in front of a function to eliminate name mangling

More info about C++ name mangling is provided by link:

Name Decoration

Example of usage:

extern "C" __declspec(dllexport) void HelloWorld();

More info about this is provided by link:

Exporting C++ Functions for Use in C-Language Executables


2. Create a module definition (.def) file and use the .def file when building the DLL

More info about this is provided by link:

Exporting from a DLL Using DEF Files

Further I describe three approach about how to create .def file.


2.1. Export C functions

In this case you could simple add function declarations in the .def file by hand.

Example of usage:

extern "C" void HelloWorld();

Example of .def file (__cdecl naming convention):

EXPORTS 
_HelloWorld

2.2. Export symbols from static library

I tried approach suggested by "user72260".

He said:

  • Firstly, you could create static library.
  • Then use "dumpbin /LINKERMEMBER" to export all symbols from static library.
  • Parse the output.
  • Put all results in a .def file.
  • Create dll with the .def file.

I used this approach, but it's not very convinient to always create two builds (one as a static and the other as a dynamic library). However, I have to admit, this approach really works.


2.3. Export symbols from .obj files or with help of the CMake


2.3.1. With CMake usage

Important notice: You don't need any export macros to a classes or functions!

Important notice: You can't use /GL (Whole Program Optimization) when use this approach!

  • Create CMake project based on the "CMakeLists.txt" file.
  • Add the following line to the "CMakeLists.txt" file:
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  • Then create Visual Studio project with help of "CMake (cmake-gui)".
  • Compile the project.

Example of usage:

Root folder

CMakeLists.txt (Root folder)

cmake_minimum_required(VERSION 2.6)
project(cmake_export_all)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")

set(SOURCE_EXE main.cpp)

include_directories(foo)

add_executable(main ${SOURCE_EXE})

add_subdirectory(foo)

target_link_libraries(main foo)

main.cpp (Root folder)

#include "foo.h"

int main() {
HelloWorld();

return 0;
}

Foo folder (Root folder / Foo folder)

CMakeLists.txt (Foo folder)

project(foo)

set(SOURCE_LIB foo.cpp)

add_library(foo SHARED ${SOURCE_LIB})

foo.h (Foo folder)

void HelloWorld();

foo.cpp (Foo folder)

#include <iostream>

void HelloWorld() {
std::cout << "Hello World!" << std::endl;
}

Link to the example project again:

cmake_windows_export_all_symbols

CMake uses the different from "2.2. Export symbols from static library" approach.

It does the following:

1) Create "objects.txt" file in the build directory with information of .obj files are used in a dll.

2) Compile the dll, that is create .obj files.

3) Based on "objects.txt" file information extract all symbols from .obj file.

Example of usage:

DUMPBIN /SYMBOLS example.obj > log.txt

More info about this is provided by link:

/SYMBOLS

4) Parse extracted from .obj file information.

In my opinion I would use calling convection, for example "__cdecl/__fastcall", "SECTx/UNDEF" symbol field (the third column), "External/Static" symbol field (the fifth column), "??", "?" information for parsing an .obj files.

I don't know how exactly CMake parse an .obj file.
However, CMake is open source, so you could find out if it's interested for you.

Link to the CMake project:

CMake_github

5) Put all exported symbols in a .def file.

6) Link a dll with usage of a .def created file.

Steps 4)-5), that is parse .obj files and create a .def file before linking and using the .def file CMake does with help of "Pre-Link event".
While "Pre-Link event" fires you could call any program you want.
So in case of "CMake usage" "Pre-Link event" call the CMake with the following information about where to put the .def file and where the "objects.txt" file and with argument "-E __create_def".
You could check this information by creating CMake Visusal Studio project with "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" and then check the ".vcxproj" project file for dll.

If you try to compile a project without "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" or with "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)" you will get linking errors, due to the fact that symbols are not exported from a dll.

More info about this is provided by link:

Understanding Custom Build Steps and Build Events


2.3.2. Without CMake usage

You simple could create a small program for parsing .obj file by youself without CMake usege. Hovewer, I have to admit that CMake is very usefull program especially for cross-platform development.

dlopen() .so fails to find symbols in a stripped executable

man ld:

   -E
--export-dynamic
--no-export-dynamic
When creating a dynamically linked executable, using the -E option or the --export-dynamic option causes the linker to add all symbols to the dynamic symbol table. The
dynamic symbol table is the set of symbols which are visible from dynamic objects at run time.

If you do not use either of these options (or use the --no-export-dynamic option to restore the default behavior), the dynamic symbol table will normally contain only those
symbols which are referenced by some dynamic object mentioned in the link.

If you use "dlopen" to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably
need to use this option when linking the program itself.

You can also use the dynamic list to control what symbols should be added to the dynamic symbol table if the output format supports it. See the description of
--dynamic-list.

Note that this option is specific to ELF targeted ports. PE targets support a similar function to export all symbols from a DLL or EXE; see the description of
--export-all-symbols below.

You can also pass the -rdynamic option to gcc/g++ (as noted int the comment). Depending on how you setup your make script, this will be convenient

Why nm libc.so reports no symbols?

By default, nm reads the .symtab section in ELF objects, which is optional in non-relocatable objects. With the -D/--dynamic option, you can instruct nm to read the dynamic symbol table (which are the symbols actually used at run time). You may also want to use --with-symbol-versions because glibc uses symbol versioning extensively.

Alternatively, you can use eu-readelf --symbols=.dynsym or objdump -Tw. (readelf -sDW does not include symbol versioning information.)

libtool linkage - global state initalization of convenience libraries

This answer might require too many code changes for you, but I'll mention it. As I mentioned before, the convenience library model is a kind of static linkage where libraries are collated together before final linkage to an encapsulating library. Only in this case the "library" is an executable. So I'd imagine that stuff in the unnamed namespace (static variables essentially), especially unreferenced variables would be removed. With the above code, it worked as I kind of expected it to.

I was able to get registerModule to print it's message without special linker tricks in a convenience library like this:

somemodule.cpp

// in global scope
namespace registration {
bool somemodule = ModuleShare::registerModule<SomeModule>("SomeModule");
}

someapp.cpp

// somewhere
namespace registration {
extern bool somemodule;
... // and all the other registration bools
}

// in some code that does initialization, possibly
if (!(registration::somemodule && ...)) {
// consequences of initialization failure
}

How to have CMake export symbols automatically on Windows?

According to WIN32 (LD):

… the default auto-export behavior will be disabled if either of the following are true:

  • A DEF file is used.

  • Any symbol in any object file was marked with the __declspec(dllexport) attribute.

In this case, the --export-all-symbols linker option forces the auto-export functionality and exports all symbols, except some special ones. Therefore, to also export bar_funcA without modifying C/C++ codes, add this line in src/bar/CMakeLists.txt:

target_link_options(bar PRIVATE "-Wl,--export-all-symbols")


Related Topics



Leave a reply



Submit