Sharing a global/static variable between a process and DLL - c++

I'd like to share a static/global variable only between a process and a dll that is invoked by the process. The exe and dll are in the same memory address space. I don't want the variable to be shared among other processes.
Elaboration of the problem:
Say that there is a static/global variable x in a.cpp. Both the exe foo.exe and the dll bar.dll have a.cpp, so the variable x is in both images.
Now, foo.exe dynamically loads (or statically) bar.dll. Then, the problem is whether the variable x is shared by the exe and dll, or not.
In Windows, these two guys never share the x: the exe and dll will have a separate copy of x. However, in Linux, the exe and dll do share the variable x.
Unfortunately, I want the behavior of Linux. I first considered using pragma data_seg on Windows. However, even if I correctly setup the shared data segment, foo.exe and bar.dll never shares the x. Recall that bar.dll is loaded into the address space of foo.exe. However, if I run another instance of foo.exe, then x is shared. But, I don't want x to be shared by different processes. So, using data_seg was failed.
I may it use a memory-mapped file by making an unique name between exe and dll, which I'm trying now.
Two questions:
Why the behavior of Linux and Windows is different? Can anyone explain more about this?
What would be most easiest way to solve this problem on Windows?

To get the behavior of linux where both the main program and a dll share the same x, you can export that variable from either the dll, or the main program. The other module must import that variable.
You do this by using DEF files (see microsoft's documentation), or by marking the uses with the variable with __declspec(dllexport) where it's defined, and __declspec(dllimport) in any other module it's used (see microsoft's documentation). This is the same as how any function, object, or variable is shared between modules in windows.
In the case where you'd like a program to load a library at runtime, but the main program may have to use the variable before the library is loaded, the program should export the variable, and the dll should import it. There is a little bit of a chicken and egg problem here because the dll depends on the main program, and the main program depends on the dll. See http://www.lurklurk.org/linkers/linkers.html#wincircular
I've written an example of how you can do this using both Microsoft's compiler and mingw (gcc in windows), including all the different ways a program and a library can link to each other (statically, dll loaded at program start, dll loaded during runtime)
main.h
#ifndef MAIN_H
#define MAIN_H
// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate
#ifndef EXPLICIT_MAIN
LINKAGE int x;
#endif // EXPLICIT_MAIN
#endif // MAIN_H
main.c
#ifdef EXPLICIT_DLL
#include "dyn_link.h"
#endif // EXPLICIT_DLL
#include <stdio.h>
#include "linkage_exporting.h"
#include "main.h"
#include "linkage_importing.h"
#include "dll.h"
FNCALL_DLL get_call_dll(void);
int main(int argc, char* argv[])
{
FNCALL_DLL fncall_dll;
fncall_dll = get_call_dll();
if (fncall_dll)
{
x = 42;
printf("Address of x as seen from main() in main.c: %p\n", &x);
printf("x is set to %i in main()\n", x);
fncall_dll();
// could also be called as (*fncall_dll)();
// if you want to be explicit that fncall_dll is a function pointer
printf("Value of x as seen from main() after call to call_dll(): %i\n", x);
}
return 0;
}
FNCALL_DLL get_call_dll(void)
{
#ifdef EXPLICIT_DLL
return get_ptr("dll.dll", "call_dll");
#else
return call_dll;
#endif // EXPLICIT_DLL
}
dll.h
#ifndef DLL_H
#define DLL_H
// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate
// declaration of type to hold a
// pointer to the function
typedef void(*FNCALL_DLL)(void);
#ifndef EXPLICIT_DLL
LINKAGE void call_dll(void);
#endif // EXPLICIT_DLL
#endif // DLL_H
dll.c
#ifdef EXPLICIT_MAIN
#include "dyn_link.h"
#endif // EXPLICIT_MAIN
#include <stdio.h>
#include "linkage_importing.h"
#include "main.h"
#include "linkage_exporting.h"
#include "dll.h"
int* get_x_ptr(void);
LINKAGE void call_dll(void)
{
int* x_ptr;
x_ptr = get_x_ptr();
if (x_ptr)
{
printf("Address of x as seen from call_dll() in dll.c: %p\n", x_ptr);
printf("Value of x as seen in call_dll: %i()\n", *x_ptr);
*x_ptr = 31415;
printf("x is set to %i in call_dll()\n", *x_ptr);
}
}
int* get_x_ptr(void)
{
#ifdef EXPLICIT_MAIN
return get_ptr("main.exe", "x"); // see note in dyn_link.c about using the main program as a library
#else
return &x;
#endif //EXPLICIT_MAIN
}
dyn_link.h
#ifndef DYN_LINK_H
#define DYN_LINK_H
// even though this function is used by both, we link it
// into both main.exe and dll.dll as necessary.
// It's not shared in a dll, because it helps us load dlls :)
void* get_ptr(const char* library, const char* object);
#endif // DYN_LINK_H
dyn_link.c
#include "dyn_link.h"
#include <windows.h>
#include <stdio.h>
void* get_ptr(const char* library, const char* object)
{
HINSTANCE hdll;
FARPROC ptr;
hdll = 0;
ptr = 0;
hdll = LoadLibrary(library);
// in a better dynamic linking library, there would be a
// function that would call FreeLibrary(hdll) to cleanup
//
// in the case where you want to load an object in the main
// program, you can use
// hdll = GetModuleHandle(NULL);
// because there's no need to call LoadLibrary on the
// executable if you can get its handle by some other means.
if (hdll)
{
printf("Loaded library %s\n", library);
ptr = GetProcAddress(hdll, object);
if (ptr)
{
printf("Found %s in %s\n", object, library);
} else {
printf("Could not find %s in %s\n", object, library);
}
} else {
printf("Could not load library %s\n", library);
}
return ptr;
}
linkage_importing.h
// sets up some macros to handle when to use "__declspec(dllexport)",
// "__declspec(dllimport)", "extern", or nothing.
// when using the LINKAGE macro (or including a header that does):
// use "#include <linkage_importing.h>" to make the LINKAGE macro
// do the right thing for importing (when using functions,
// variables, etc...)
//
// use "#include <linkage_exporting.h>" to make the LINKAGE macro
// do the right thing for exporting (when declaring functions,
// variables, etc).
//
// You can include either file at any time to change the meaning of
// LINKAGE.
// if you declare NO_DLL these macros do not use __declspec(...), only
// "extern" as appropriate
#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
#define LINKAGE extern
#else
#define LINKAGE extern __declspec(dllimport)
#endif
linkage_exporting.h
// See linkage_importing.h to learn how this is used
#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
#define LINKAGE
#else
#define LINKAGE __declspec(dllexport)
#endif
build mingw explicit both.sh
#! /bin/bash
echo Building configuration where both main
echo and dll link explicitly to each other
rm -rf mingw_explicit_both
mkdir -p mingw_explicit_both/obj
cd mingw_explicit_both/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c
#create the dll from its object code the normal way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a
# create the executable
gcc -o main.exe main.o dyn_link.o
mv dll.dll ..
mv main.exe ..
cd ..
build mingw explicit dll.sh
#! /bin/bash
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rm -rf mingw_explicit_dll
mkdir -p mingw_explicit_dll/obj
cd mingw_explicit_dll/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c
# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a
#create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o dyn_link.o main.a -Wl,--out-implib,libdll.a
# create the executable
gcc -o main.exe main.o dyn_link.o
mv dll.dll ..
mv main.exe ..
cd ..
build mingw explicit main.sh
#! /bin/bash
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rm -rf mingw_explicit_main
mkdir -p mingw_explicit_main/obj
cd mingw_explicit_main/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c ../../main.c
gcc -c ../../dyn_link.c
# since the dll will link dynamically and explicitly with main, there is no need
# to create a linking library for main, and the dll can be built the regular way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a
# create the executable (main still links with dll implicitly)
gcc -o main.exe main.o -L. -ldll
mv dll.dll ..
mv main.exe ..
cd ..
build mingw implicit.sh
#! /bin/bash
echo Building configuration where main and
echo dll implicitly link to each other
rm -rf mingw_implicit
mkdir -p mingw_implicit/obj
cd mingw_implicit/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c ../../main.c
# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a
# create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o main.a -Wl,--out-implib,libdll.a
# create the executable (exe needs to know about dll's exports)
gcc -o main.exe main.o -L. -ldll
mv dll.dll ..
mv main.exe ..
cd ..
build mingw static.sh
#! /bin/bash
echo Building configuration where main and dll
echo statically link to each other
rm -rf mingw_static
mkdir -p mingw_static/obj
cd mingw_static/obj
# compile the source code
gcc -c -DNO_DLL ../../dll.c
gcc -c -DNO_DLL ../../main.c
# create the static library
ar -rcs dll.a dll.o
# link the executable
gcc -o main.exe main.o dll.a
mv main.exe ../
cd ..
build msvc explicit both.bat
#echo off
echo Building configuration where both main
echo and dll link explicitly to each other
rd /s /q win_explicit_both
md win_explicit_both\obj
cd win_explicit_both\obj
rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem create the dll from its object code the normal way
link /nologo /dll dll.obj dyn_link.obj
rem create the executable
link /nologo main.obj dyn_link.obj
move dll.dll ..\
move main.exe ..\
cd ..
build msvc explicit dll.bat
#echo off
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rd /s /q win_explicit_dll
md win_explicit_dll\obj
cd win_explicit_dll\obj
rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj
rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib
rem create the executable
link /nologo main.obj dyn_link.obj
move dll.dll ..\
move main.exe ..\
cd ..
build msvc explicit main.bat
#echo off
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rd /s /q win_explicit_main
md win_explicit_main\obj
cd win_explicit_main\obj
rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem since the dll will link dynamically and explicitly with main, there is no need
rem to create a linking library for main, and the dll can be built the regular way
link /nologo /dll dll.obj dyn_link.obj
rem create the executable (main still links with dll implicitly)
link /nologo main.obj dll.lib
move dll.dll ..\
move main.exe ..\
cd ..
build msvc implicit.bat
#echo off
echo Building configuration where main and
echo dll implicitly link to each other
rd /s /q win_implicit
md win_implicit\obj
cd win_implicit\obj
rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c ..\..\main.c
rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj
rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib
rem create the executable (exe needs to know about dll's exports)
link /nologo main.obj dll.lib
move dll.dll ..\
move main.exe ..\
cd ..
build msvc static.bat
#echo off
echo Building configuration where main and dll
echo statically link to each other
rd /s /q win_static
md win_static\obj
cd win_static\obj
rem compile the source code
cl /nologo /DNO_DLL /c ..\..\dll.c
cl /nologo /DNO_DLL /c ..\..\main.c
rem create the static library
lib /nologo dll.obj
rem link the executable
link /nologo main.obj dll.lib
move main.exe ..\
cd ..

First, I found that this article was a very interesting and a concise read on dynamic link libraries (the article is only specific to Linux, but the concepts surely apply to windows as well and you might get some insight as to the different behaviour you are seeing). Especially the fundamental difference between static and dynamic loading.
I think what you want or are trying to implement is a "cross-module singleton" pattern. If you read the answers to this thread, I don't know how I could possibly answer your question any better than Ben Voigt answered that post. I have implemented a cross-module singleton before (a few times actually) using the method he describes, and it works like a charm.
Of course, you will not be able to retain the cleaniness of just having the global variable sit there in the cpp file. You will have to use a static pointer and some accessor functions and reference counting. But it can work. I'm not so sure how it would be possible to avoid that foo.exe and foo.exe share the same instance of global data one bar.dll, I never had to do that and can't really think of a way to do it, sorry.

I found this to be such an interesting question that I took the time to write an extensive tutorial on how to use DLL's to share data among multiple DLLs (either implicitly, or explicitly linked) but also make sure the data is not shared among separate processes of the same executable file.
You can find the full article here: http://3dgep.com/?p=1759
A solution to this problem that I found to work quite well is to create a "common" or "shared" dll that defines all the data and methods that you want to share across multiple DLL's (but not shared among processes).
Let's suppose you want to define a singleton class that can be accessed from the main application code (the EXE) but you also want to access the singleton instance in shared (either implicitly or explicitly linked DLL). First, you would need to declare the singleton class in the "common" DLL:
// Export the class when compiling the DLL,
// otherwise import the class when using the DLL.
class __declspec(dllexport) MySingleton
{
public:
static MySingleton& Instance();
};
When compiling the CommonDLL project, you have to export the class declaratoin by decorating the class with __declspec(dllexport) and when you are using the DLL (in the application for example), the class definition needs to be imported by decorating the class with __declspec(dllimport).
When exporting a class by decorating the class with the __declspec(dllexport) specifier, all of the class's methods and data (even private data) are exported from the DLL and usable by any DLL or EXE that implicitly links to the common DLL.
The definition of the MySingleton class might look something like this:
MySingleton& MySingleton::Instance()
{
static MySingleton instance;
return instance;
}
When compiling the common dll, two files will be produced:
The Common.DLL file which is the shared library that defines the mehthods and data exported used by the DLL.
The Common.LIB file which declares stubs for the methods and members exported from the DLL.
If you link you application against the exported LIB file, then the DLL file will be implicitly linked at runtime (as long as the DLL file is found in the DLL search paths) and you will have access to the singleton defined in the CommonDLL.DLL file.
Also, any shared library (plug-ins for example) that also links against the CommonDLL.LIB file will have access to the same singleton instances when dynamically loaded by the application.
For a full explanation of this solution including a source code sample, check-out the following article I posted titled "Using Dynamic Link Libraries (DLL) to Create Plug-Ins":
http://3dgep.com/?p=1759

If foo.exe always loads bar.dll then you can implement the variable in bar.dll and export it. For example, some file b.cpp compiled only into bar.dll, not into foo.exe:
__declspec(dllexport) int x;
Then import it in a source file c.cpp compiled into foo.exe:
__declspec(dllimport) int x;
However, if sometimes foo.exe doesn't load bar.dll then this won't work. Also, I'm writing this from memory and so there might be some syntactical errors, but hopefully it's enough to point you in the right direction.
I can't answer why it's different Linux.

The difference between GCC and and Visual Studio is that on Linux, it implicitly allows code to see symbols from other, dynamically linked (shared) libraries, without you the programmer having to do anything special. All the symbols are available in the shared (dynamically linked) library for the dynamic linker to resolve when the program runs. On Windows, you have to specifically export the symbol from the DLL, and also explicitly import it into the program or library that's using it. (Usually this is done via a macro (#define) that expands to have the dllexport declaration in a header file when building the dll itself, but when the header file is included by some other program using the dll, it expands to have the dllimport declaration instead. In my opinion this is a pain in the neck, and GCC's behavior is easier, since you don't have to do anything special to get the behavior you usually want.
On newer version of GCC, you can set the default to hide symbols when building a dynamic (shared) library, if you want to.

Thanks for providing various solution on this. i have looked at these option and decided to implement the cross module singleton using the Shared Memory and it worked well for me as well.
i have used Qt QSharedMemory to achieve my task but the prototype i wrote using the Win32 CreateFileMapping & etc.

If I understand your question correctly, you are statically linking a.cpp into foo.exe and bar.dll, so you get 2 instances of x.
If you created a third dll (say a.dll), and you dynamically link foo.exe and bar.dll to a.dll, you will get the behaviour you desire:
foo.exe loads a.dll and creates x.
bar.dll gets loaded and sees that
a.dll is loaded and doesn't load it
again, they share x.
Another process loads a.dll, it gets
its own x.

I have seen many answers to this question and since it is a bit tricky and unclear I would like to bring the following scenario.
We want to share a global variable between a DLL and a main program, and also allow access to this variable from different modules in the DLL and in the main program.
The variable is a BOOL indicating if the program should continue running or stop. The variable name is ShouldRun;
In the main program we need to put:
__declspec(dllexport) bool ShouldRun;
In the DLL's main module we need to put:
extern "C" BOOL __declspec(dllexport) ShouldRun = TRUE;
In any other module inside the DLL project we will use:
extern "C" BOOL ShouldRun;

Related

Why is there a distinction between linking with target object libraries and libraries using add_library and add_executable?

This is my simple CMakeLists.txt:
project(MyProject)
# Create the library from server.cpp
add_library(server OBJECT tcp_server.cpp tcp_server_priv.cpp)
# Add the current directory to the include path for this target
target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
# Create the executable from main.cpp and link it to the library
add_executable(my_server main.cpp $<TARGET_OBJECTS:server>)
I recently learned about the add_library(x OBJECT y z ...) construct; my understanding: this doesn't create a static or shared library (.a or .so), but rather forms some temporary/logical grouping of object files, which can be referenced elsewhere as that same group. I.e. elsewhere, I can refer to $<TARGET_OBJECTS:server> to refer to tcp_server.o and tcp_server_priv.o in aggregate, so the line add_executable(my_server main.cpp $<TARGET_OBJECTS:server>) means "compile main.cpp, and link it with tcp_server.o and tcp_server_priv.o to make the executable my_server".
I.e. the add_executable line does both compiling and linking.
I wanted my executable to also link with libpthread, so I tried making this change to the add_executable line:
add_executable(my_server main.cpp $<TARGET_OBJECTS:server> pthread)
...but that generated this error with cmake:
-- Configuring done
CMake Error at src/CMakeLists.txt:9 (add_executable):
Cannot find source file:
pthread
Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
.hpp .hxx .in .txx
CMake Error at src/CMakeLists.txt:9 (add_executable):
No SOURCES given to target: med_server
CMake Generate step failed. Build files cannot be regenerated correctly.
make: *** [Makefile:160: cmake_check_build_system] Error 1
Isn't the above analogous to the following, where I compile main.cpp, link object-file dependencies, and libraries in a single g++ invocation:
// tcp_server.cpp
#include <iostream>
extern void private_func();
void public_func() {
std::cout << __FUNCTION__ << std::endl;
private_func();
}
// tcp_server_priv.cpp
#include <iostream>
void private_func() {
std::cout << __FUNCTION__ << std::endl;
}
// main.cpp
#include <semaphore.h>
extern void public_func();
int main(int argc, char* argv[]) {
sem_t my_sem;
public_func();
sem_init(&my_sem, 0, 0);
sem_destroy(&my_sem);
return 0;
}
$ g++ -c ./tcp_server.cpp \
> && g++ -c ./tcp_server_priv.cpp \
> && g++ main.cpp tcp_server.o tcp_server_priv.o -lpthread \
> && ./a.out
public_func
private_func
$
?
Why can I not link a library with the add_executable statement when I can link object files?
Isn't the attempted add_executable(my_server main.cpp $<TARGET_OBJECTS:server> pthread) effectively the same as g++ main.cpp tcp_server.o tcp_server_priv.o -lpthread?
TLDR: The distinction is more apparent when you realize what the compilation process looks like.
EDIT: Link to compilation models for better understanding, NOTE: you're interested just in the first picture.
For this example I will use a static library, i.e. on linux it would be suffixed with .a on windows .lib. Let's ask ourselves what happens when you build and link this library:
The steps before are not important for the distinction, so let's start with the following step
The compiler compiles the individual .cpp (or multiple) into .o object files
These files are then linked together / archived into a library .a / .lib
Now if we want to "link" a static library:
We will actually unpack this archive .a back into the object files
We will then grab the .o object files that we compiled in our executable
Compiler does some optimizations and throws out unwanted object files
Repacks and links all the remaining object files we have, into an executable
So you can think of the distinction as such (using static library as an example):
Object files: We don't have to unpack the archive, we just need to link them with the newly created object files
Static library: We need to tell the compiler that hey, we need to unpack this first so we can link it.
The only role of CMake is to "create some sort of a configuration" for your compiler/linker in order to get the job done.
One interesting thing about the distinction between OBJECT and STATIC libraries is ( which further demonstrates what I mentioned ) is that if you use OBJECT libraries you will not take advantage of optimization.
Suppose your static library is constructed of three objects a.o b.o and c.o. If you pack it into lib.a and then link your executable against it. The optimization might exclude c.o (for example) and this will make the resulting executable smaller.
BUT if you link with object libraries a.o b.o and c.o then all of the objects will be packed with the executable.
In your
add_executable(my_server main.cpp $<TARGET_OBJECTS:server> pthread)
, the problem is with the usage of "pthread" in add_executable- not $<TARGET_OBJECTS:server>. You should be doing this to link to pthread:
target_link_libraries(my_server PRIVATE pthread)
or
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(my_app PRIVATE Threads::Threads)
See also: cmake and libpthread and the CMake object library docs.
As stated in the object library docs, this is just how CMake works. You can link to object libraries like you are doing, but you can also do it via target_link_libraries. You can use target_link_libraries to link to both object libraries (since v3.12) and shared/static libraries. With respect to target_link_libraries, there is no "distinction".

How to link to shared object library in msys2?

I have some c++ code in msys2 that I am trying to link dynamically to show how a dynamic link library works.
In linux, showing the call is no problem. stepping in gdb, we can watch the call go through the jump vector, eventually landing in the desired function.
But in msys2, they wanted to eliminated dlls and all the libraries I can find are .dll.a, I think they are really static libraries.
I build a trivial little function like this:
#include <cstdint>
extern "C" {
uint64_t f(uint64_t a, uint64_t b) {
return a + b;
}
}
compiling in the makefile with:
g++ -g -fPIC -c lib1.cc
g++ -g -shared lib1.o -o libtest1.so
When I run the file utility, it says that:
libtest1.so: PE32+ executable (DLL) (console) x86-64, for MS Windows
When I compile the code using it:
g++ -g main.cc -ltest1 -o prog
The error is -ltest1 no such file or directory.
MinGW uses the .dll extension for shared libraries, not .so.
lib??.dll.a is an import library, a shim that will load the corresponding lib??.dll at runtime.
At some point in time, you couldn't link .dlls directly, and had to link .dll.as instead. The modern MinGW can link .dlls directly, so you shouldn't need to use import libraries anymore.
-ltest1 no such file or directory
Wouldn't you get the same error on Linux? You have to specify the library search path with -L. -ltest1 needs either libtest1.a or libtest1.dll.a or libtest1.dll (perhaps some other variants are checked too).
The reason your linker cannot find the library is because your current working directory is not in the search path for libraries. Add -L. to your linking command.
It is untrue that MSYS2 "wanted to eliminate DLLs". Just run ls /mingw64/bin/*.dll and you will see plenty of DLLs (assuming you have some MINGW64 packages installed). The .dll.a files used for linking are called import libraries.

Why doesn't the linker complain of duplicate symbols?

I have a dummy.hpp
#ifndef DUMMY
#define DUMMY
void dummy();
#endif
and a dummy.cpp
#include <iostream>
void dummy() {
std::cerr << "dummy" << std::endl;
}
and a main.cpp which use dummy()
#include "dummy.hpp"
int main(){
dummy();
return 0;
}
Then I compiled dummy.cpp to three libraries, libdummy1.a, libdummy2.a, libdummy.so:
g++ -c -fPIC dummy.cpp
ar rvs libdummy1.a dummy.o
ar rvs libdummy2.a dummy.o
g++ -shared -fPIC -o libdummy.so dummy.cpp
When I try compile main and link the dummy libs
g++ -o main main.cpp -L. -ldummy1 -ldummy2
There is no duplicate symbol error produced by linker. Why does this happen when I link two identical libraries statically?
When I try
g++ -o main main.cpp -L. -ldummy1 -ldummy
There is also no duplicate symbol error, Why?
The loader seems always to choose dynamic libs and not the code compiled in the .o files.
Does it mean the same symbol is always loaded from the .so file if it is both in a .a and a .so file?
Does it mean symbols in the static symbol table in static library never conflict with those in the dynamic symbol table in a .so file?
There's no error in either Scenario 1 (dual static libraries) or Scenario 2 (static and shared libraries) because the linker takes the first object file from a static library, or the first shared library, that it encounters that provides a definition of a symbol it has not yet got a definition for. It simply ignores any later definitions of the same symbol because it already has a good one. In general, the linker only takes what it needs from a library. With static libraries, that's strictly true. With shared libraries, all the symbols in the shared library are available if it satisfied any missing symbol; with some linkers, the symbols of the shared library may be available regardless, but other versions only record the use a shared library if that shared library provides at least one definition.
It's also why you need to link libraries after object files. You could add dummy.o to your linking commands and as long as that appears before the libraries, there'll be no trouble. Add the dummy.o file after libraries and you'll get doubly-defined symbol errors.
The only time you run into problems with this double definitions is if there's an object file in Library 1 that defines both dummy and extra, and there's an object file in Library 2 that defines both dummy and alternative, and the code needs the definitions of both extra and alternative — then you have duplicate definitions of dummy that cause trouble. Indeed, the object files could be in a single library and would cause trouble.
Consider:
/* file1.h */
extern void dummy();
extern int extra(int);
/* file1.cpp */
#include "file1.h"
#include <iostream>
void dummy() { std::cerr << "dummy() from " << __FILE__ << '\n'; }
int extra(int i) { return i + 37; }
/* file2.h */
extern void dummy();
extern int alternative(int);
/* file2.cpp */
#include "file2.h"
#include <iostream>
void dummy() { std::cerr << "dummy() from " << __FILE__ << '\n'; }
int alternative(int i) { return -i; }
/* main.cpp */
#include "file1.h"
#include "file2.h"
int main()
{
return extra(alternative(54));
}
You won't be able to link the object files from the three source files shown because of the double-definition of dummy, even though the main code does not call dummy().
Regarding:
The loader seems always to choose dynamic libs and not compiled in the .o files.
No; the linker always attempts to load object files unconditionally. It scans libraries as it encounters them on the command line, collecting definitions it needs. If the object files precede the libraries, there's not a problem unless two of the object files define the same symbol (does 'one definition rule' ring any bells?). If some of the object files follow libaries, you can run into conflicts if libraries define symbols that the later object files define. Note that when it starts out, the linker is looking for a definition of main. It collects the defined symbols and referenced symbols from each object file it is told about, and keeps adding code (from libraries) until all the referenced symbols are defined.
Does it means the same symbol is always loaded from .so file, if it is both in .a and .so file?
No; it depends which was encountered first. If the .a was encountered first, the .o file is effectively copied from the library into the executable (and the symbol in the shared library is ignored because there's already a definition for it in the executable). If the .so was encountered first, the definition in the .a is ignored because the linker is no longer looking for a definition of that symbol — it's already got one.
Does it mean that symbols in static symbol table in a static library are never in conflict with those in dynamic symbol table in .so file?
You can have conflicts, but the first definition encountered resolves the symbol for the linker. It only runs into conflicts if the code that satisfies the reference causes a conflict by defining other symbols that are needed.
If I link 2 shared libs, can I get conflicts and the link phase failed?
As I noted in a comment:
My immediate reaction is "Yes, you can". It would depend on the content of the two shared libraries, but you could run into problems, I believe. […cogitation…] How would you show this problem? … It's not as easy as it seems at first sight. What is required to demonstrate such a problem? … Or am I overthinking this? … […time to go play with some sample code…]
After some experimentation, my provisional, empirical answer is "No, you can't" (or "No, on at least some systems, you don't run into a conflict"). I'm glad I prevaricated.
Taking the code shown above (2 headers, 3 source files), and running with GCC 5.3.0 on Mac OS X 10.10.5 (Yosemite), I can run:
$ g++ -O -c main.cpp
$ g++ -O -c file1.cpp
$ g++ -O -c file2.cpp
$ g++ -shared -o libfile2.so file2.o
$ g++ -shared -o libfile1.so file1.o
$ g++ -o test2 main.o -L. -lfile1 -lfile2
$ ./test2
$ echo $?
239
$ otool -L test2
test2:
libfile2.so (compatibility version 0.0.0, current version 0.0.0)
libfile1.so (compatibility version 0.0.0, current version 0.0.0)
/opt/gcc/v5.3.0/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.21.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/opt/gcc/v5.3.0/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
$
It is aconventional to use .so as the extension on Mac OS X (it's usually .dylib), but it seems to work.
Then I revised the code in the .cpp files so that extra() calls dummy() before the return, and so does alternative() and main(). After recompiling and rebuilding the shared libraries, I ran the programs. The first line of output is from the dummy() called by main(). Then you get the other two lines produced by alternative() and extra() in that order because the calling sequence for return extra(alternative(54)); demands that.
$ g++ -o test2 main.o -L. -lfile1 -lfile2
$ ./test2
dummy() from file1.cpp
dummy() from file2.cpp
dummy() from file1.cpp
$ g++ -o test2 main.o -L. -lfile2 -lfile1
$ ./test2
dummy() from file2.cpp
dummy() from file2.cpp
dummy() from file1.cpp
$
Note that the function called by main() is the first one that appears in the libraries it is linked with. But (on Mac OS X 10.10.5 at least) the linker does not run into a conflict. Note, though, that the code in each shared object calls 'its own' version of dummy() — there is disagreement between the two shared libraries about which function is dummy(). (It would be interesting to have the dummy() function in separate object files in the shared libraries; then which version of dummy() gets called?) But in the extremely simple scenario shown, the main() function manages to call just one of the dummy() functions. (Note that I'd not be surprised to find differences between platforms for this behaviour. I've identified where I tested the code. Please let me know if you find different behaviour on some platform.)

Embed COM type library resouce (TLB) in MinGW-built DLL

I have a COM type library built with midl, call it "mylib.tlb". I want to embed it in a DLL, "mylib.dll" which is compiled and linked with MinGW. The DLL "mylib.dll" also contains a function myfunc(). I want to be able to embed "mylib.tlb" as a resource within "mylib.dll" so that myfunc()—which is also within "mylib.dll"—can load "mylib.tlb" using the COM function LoadTypeLibEx().
In other words:
void myfunc() // a function living within "mylib.dll"
{
// ...
ITypeLib * result(0);
HRESULT hr = LoadTypeLibEx(path_to_this_dll, REGKIND_NONE, &result);
// should successfully load "mylib.tlb" into result!!!
}
This isn't working for me and I'm not sure why. LoadTypeLibEx() is returning -2147312566 = 0x80029c4a = TYPE_E_CANTLOADLIBRARY. I can't tell if that's because it can't load the DLL at all, or if it can't find the type library within the DLL. I have verified that my path_to_this_dll variable contains the path to "mylib.dll", so I'm hoping it's the latter.
I am trying to build "mylib.tlb" into "mylib.dll" using the following MinGW tool command line:
$ windres myres.rc myres.o
$ ar rcs mylib.a a.o b.o ... myres.o ... x.o
$ g++ -o mylib.dll -shared ... mylib.a ...
Where "myres.rc" just looks like this:
1000 typelib "mylib.tlb"
When I build "mylib.dll" I can verify that it contains a bunch of other resources (icons, cursors, and so on) using a program called ResourceHacker, but I can't tell from ResourceHacker whether the TLB made it into the DLL.
Is my resource script ("myres.rc") right?
What other resource tools could I use to check if the TLB made it into the DLL?
Am I doing something wrong in principle?
EDIT: I noticed that the TLB file contains the string "MIDL", so I tried grepping for that in various files. Somehow the type library resource isn't getting into the DLL:
$ grep MIDL mylib.tlb
Binary file mylib.tlb matches
$ grep MIDL myres.o
Binary file myres.o matches
$ grep MIDL mylib.a
Binary file mylib.a matches
$ grep MIDL mylib.dll
$ echo $?
1
Why would the linker not put the TLB resource into the DLL?
The problem is that the MinGW linker can only handle one object file containing resources. It takes the resources out of the first one and ignores all of the other ones.
So I was doing:
$ g++ -o mylib.dll -shared main_resources.o myres.o
where "myres.o" contains the TLB. If I invert the order of the objects on the command line, the DLL contains the TLB and none of the other resources. Other than that, my code in the question section works fine.
See:
WindRes screws up RC output
W32-mingw: windres cannot handle concatenated .res files

GCC How to export a function from static library

I want to create a shared library from several static libs using GCC under OS X.
In some static libs, there's no code in shared library call it, I just want to export the symbols in these static libs. This works under debug mode, but doesn't under release mode (especially when I enable the dead code striping). I can understand the reason, gcc think these functions on static libs are never used. but how can I force gcc to include these symbols?
I already tried adding -u option for loader, but it only generates a 'local' symbol. how to make linker generate an export symbol?
Also, I'm wondering if there's a way to add the linker directives in source code, just like the MSVC #pragrma comment(linker, "/INCLUDE:xxxx")
the function I defined in static lib is like:
extern "C"
void test() {}
Thanks in advance!
-Jonny
Have you tried --whole-archive?
Use ar to disassemble the static libraries into their constituent object files. Then link those objects together to make the shared library.
ar -x libstatic.a
(produces a bunch of *.o files)
gcc -shared -olibshared.so *.o # Linux
ld -dylib -olibshared.dylib *.o # Mac OSX