How do I create static and dynamic libraries for Windows using g++?
I've found a few commands for Linux for creating .so files and I've tried to apply them on a Windows shell, but they build .dll files that my applications fail to link with at runtime.
I've only managed to build .dll files using Visual C++ but I would like to build them manually on the command line, preferably using g++. I would also like to know how to build static libraries too for Windows.
You need to prefix with the attribute :
__declspec(dllexport)...
all the features you want to expose.
See this.
Example for a C function:
__declspec(dllexport) int __cdecl Add(int a, int b)
{
return (a + b);
}
This can be simplified using MACROS: everything is explained on this helpful page.
For C++ classes, you only need to prefix each class (not every single method)
I usually do it that way :
Note : The following also ensures portability...
Include File :
// my_macros.h
//
// Stuffs required under Windoz to export classes properly
// from the shared library...
// USAGE :
// - Add "-DBUILD_LIB" to the compiler options
//
#ifdef __WIN32__
#ifdef BUILD_LIB
#define LIB_CLASS __declspec(dllexport)
#else
#define LIB_CLASS __declspec(dllimport)
#endif
#else
#define LIB_CLASS // Linux & other Unices : leave it blank !
#endif
Usage :
#include "my_macros.h"
class LIB_CLASS MyClass {
}
Then, to build, simply :
Pass the option -DBUILD_LIB to the usual compiler command line
Pass the option -shared to the usual linker command line
Related
I made a C++/CLI wrapper for using a C# DLL in a C++ application. I used Visual Studio to manage the projects and manage the dependencies, and I got it to work that way.
But I can't get it to work when I use CMake to link the library that Visual Studio built for me.
cmake_minimum_required (VERSION 3.12)
project(playground CXX)
SET(CMAKE_CXX_STANDARD 17)
set(PLAYGROUND_SOURCE_DIR ${CCMAKE_CURRENT_SOURCE_DIR})
set(PLAYGROUND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(PLAYGROUND_SRC
main.cpp)
add_executable(Playground ${PLAYGROUND_SRC} ${PLAYGROUND_HDR})
find_library(comm_dll CommWrapper Lib/CommDLL)
target_link_libraries(Playground PUBLIC
${comm_dll}
)
Using this method gets me an "unresolved external symbol error". I have the .dll, .lib and .h file in the same folder.
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries. If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side: I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.
I have a C++ Visual Studio 2015 project consisting of
1 Windows API executable, 1 windows console executable, and 1 dll shared by both executables.
I have a #define USEWINDOWS in the Windows API main.cpp file
I don't have this defined in the console app
In the DLL, I would like to do an #ifdef USEWINDOWS statement, but the scope of the #define seems to be only valid to the Win32 executable, not in the dll.
How can I extend this #define to the DLL without having it affect the undefined USEWINDOWS in the console app?
Thanks
The DLL is shared by both executables, hence there is only one implementation available and therefore you can't use implementation specific compilation flags.
You'll need a runtime flag, i.e. some API parameter which tells the DLL code that it is OK to use "windows stuff". E.g.
api.h
void someAPI(...., bool useWindows);
dll.c
#include "api.h"
void someAPI(...., bool useWindows) {
...
if (useWindows) {
// do "windows stuff" here
}
...
}
app.c
#include "api.h"
...
someAPI(...., true);
console.c
#include "api.h"
...
someAPI(...., false);
(not tested by compilation, but you should get the drift...)
Toolchain is the SW4STM32, gcc, processor is STM32F303K8 (Nucleo 303K8), minimal test project with no actual user code at all.
The process how to convert a project generated by ST CubeMX is well documented and apparently works. However, when i specify FreeRTOS in Cube, linker fails to find the init function MX_FREERTOS_Init(). The function prototype is included in main.cpp and the definition exists in another source file (freertos.c). This works in C but when converting the project to C++ the linker fails to link the function.
The C2C++ conversion i did as follows:
add ccnature to the .project file
copy main.c to main.cpp (& remove main.c from the build)
duplicate gcc compiler settings over to g++ in project properties
point linker script to the one in the project directory
The above enable Eclipse to compile main using g++ and to link using G++ linker. However linking consistently fails in ...\Debug/../Src/main.cpp:97: undefined reference to `MX_FREERTOS_Init()'
What is remarkable is that even when i delete all references to MX_FREERTOS_Init() from main.cpp so that the text simply does not exist anywhere, linker STILL fails exactly the same. It even reports the same line number even though the text is completely different. This behavior does not change never mind if i clean the project, rebuild and refresh all indexes etc etc.
Any suggestions anyone? Or do i have to skip specifying FreeRTOS in Cube and do it all manually?
I have the same question using atollic for stm32,
solved by adding extern "C" to main.cpp
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config();
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
#ifdef __cplusplus
}
#endif
/* USER CODE END PFP */
I have faced with the same issue.
So, I would like to suggest renaming freertos.c file to freertos.cpp.
I would suggest a C++ RTOS for example the free disortos. (Google it)
I have tried without success to create a C-language function in PostgreSQL from a module that depends on another DLL in Windows.
For example, let's suppose I want to create the sumfunction that adds two numbers returned by the numberfunction that is in its own DLL.
The code for number.h is:
#ifndef NUMBER_H
#define NUMBER_H
#ifdef NUMBER_EXPORTS
#define NUMBER_API __declspec(dllexport)
#else
#define NUMBER_API __declspec(dllimport)
#endif
extern "C" NUMBER_API int number();
#endif
and the code for number.cpp is:
#include "number.h"
extern "C" int number() { return 1; }
The code for sum.cpp is:
extern "C" {
#include <postgres.h>
#include <fmgr.h>
#include <utils/geo_decls.h>
#include "number.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
__declspec(dllexport) PG_FUNCTION_INFO_V1(sum);
Datum sum(PG_FUNCTION_ARGS)
{
int32 a {number()};
int32 b {number()};
int32 result {a + b};
PG_RETURN_INT32(result);
}
} // extern "C"
Suppossing that PostgreSQL is installed on C:\Program Files\PostgreSQL\9.5, I create number.dll and sum.dll using this build.bat file:
SET PG_DIR=C:\Program Files\PostgreSQL\9.5
SET PG_INCLUDES=/I%PG_DIR%\include /I%PG_DIR%\include\server /I%PG_DIR%\include\server\port\win32
CL number.cpp /EHsc /MD /DNUMBER_EXPORTS /LD
CL sum.cpp /EHsc /MD %PG_INCLUDES% /LD /link number.lib
Then I copy both DLLs to C:\Program Files\PostgreSQL\9.5\lib and write the SQL for creating the function in sum.sql:
CREATE OR REPLACE FUNCTION sum() RETURNS void AS
'sum'
LANGUAGE C STRICT;
After running psql -U postgres -f sum.sql, I get the following error:
psql:sum.sql:3: ERROR: could not load library "C:/Program Files/PostgreSQL/9.5/lib/sum.dll": The specified module could not be found.
Note that this error is different from a "file not found" error. It seems that PostgreSQL finds the file, but does not recognize it as a valid module. However, if I create a static library of num.cpp instead and link it against sum.dll, then the function is created successfully. In other words, PostgreSQL loads the module only if it contains all the code it needs.
Why is this happening and how could I make PostgreSQL to know about number.dll when creating the sum function?
The directories of the dependent DLLs must exist in PATH before PostgreSQL server is started.
Go to:
Control Panel
System and Security
System
Advanced System Settings
Advanced
Environment Variables
Path
Open it and add the full path of all directories where the dependent DLLs reside. Restart the PostgreSQL server and done, psql will execute the C-module successfully.
I have a very trivial problem including a chain of C libraries into a C++ main project. I've experience with C but it's the first time that I'm programming in C++.
The structure of the project is a single folder with inside:
main.cpp
Mylib_1.c
Mylib_1.h
Mylib_2.c
Mylib_2.h
main calls -> Mylib_1.h that calls -> My_lib2.h
//main.cpp
#include "Mylib_1.h"
//Mylib_1.h
#include "Mylib_2.h"
main contains both Mylib_1 and Mylib_2 functions and typedef structs
Mylib_1 uses typedef structs and functions of Mylib_2
Everything inside each Mylib_x.h is wrapped between extern "C", like this:
#ifndef __MYLIB_X_H
#define __MYLIB_X_H
#ifdef __cplusplus
extern "C" {
#endif
mycode
#ifdef __cplusplus
}
#endif
#endif
But when I try to compile it with eclipse kepler on Ubuntu 12.04 x64, I get:
Mylib_1.h error: Mylib_2_type_t does not name a type
main.cpp error: Mylib_2_function1 was not declared in this scope
...
Only the above sections are marked as error in eclipse, the header looks included fine.
Furthermore according to eclipse, the __cplusplus flag is false into Mylib_2.h but true into Mylib_1.h
Thinking of some eclipse error, I've tried to manually build the project via g++ (v4.6.3) but I got the same exact problem when I've tried to link the libraries .o with the main.cpp
Seems stupid but I can't figure out what could it be. Any suggestion?
Thank you
Have you checked that your lines
#ifndef __MYLIB_X_H
#define __MYLIB_X_H
are really different for the two files,
e.g. _MYLIB1_H and _MYLIB2_H?