I'm trying to figure a "clean way" of using the default preprocessor definitions to determine what parts of my code should be compiled based on the platform and compiler.
My current test setup involves a Windows machine with Visual C++ compiler and a Debian with g++ compiler.
Currently I have something like this:
#if defined (__GNUG__)
#define ASMMath_EI __attribute__ ((__visibility__("default")))
#elif defined (WIN32)
#ifdef ASMMath_EXPORTS
#define ASMMath_EI __declspec(dllexport)
#else
#define ASMMath_EI __declspec(dllimport)
#endif
#endif
extern void ASMMath_EI AsmProblemOne();
And it works, but I figure there might and must be some better definitions I can check for. Or perhaps some more ideal way with CMake?
Suggestions?
There is a nice listing of Compiler, Operating System, and Architecture preprocessor names at those links. You could branch for the systems and compilers you care about supporting/detecting. Additionally a lot of this work is already done in boost/config/ (see boost/config/select_compiler_config.hpp as one example for compiler flags) using Boost headers. Not everyone likes including Boost, which is why the first set of links is generic from library specific support.
Answered by the OP in a question edit:
From what I gather the following would be ideal way to implement this:
// MasterHeader.h
#if defined _MSC_VER // Defined by visual studio
#define PROJ_TMP_DLL_IMPORT __declspec(dllimport)
#define PROJ_TMP_DLL_EXPORT __declspec(dllexport)
#else
#if __GNUC__ >= 4 // Defined by GNU C Compiler. Also for C++
#define PROJ_TMP_DLL_IMPORT __attribute__ ((visibility ("default")))
#define PROJ_TMP_DLL_EXPORT __attribute__ ((visibility ("default")))
#else
#define PROJ_TMP_DLL_IMPORT
#define PROJ_TMP_DLL_EXPORT
#endif
#endif
#ifdef PROJ_EXPORTS
#define PROJ_API PROJ_TMP_DLL_EXPORT
#else
#define PROJ_API PROJ_TMP_DLL_IMPORT
#endif
-
// File.h
#include "MasterHeader.h"
extern void PROJ_API SomeFunction();
Related
I did the dll tutorial from codeguru.com. There are the following lines in the header:
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
But: If I use it as suggested, I get an error during compilation (defined as import). If I exchange dllexport with dllimport and vice versa, it compiles fine and the call from another application works fine. Like this:
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllimport)
#else
#define DECLDIR __declspec(dllexport)
#endif
Is this an error in the tutorial, or am I missing something?
I use mingw and the gcc-compiler. As some might notice, I asked something similar in the comments there.
In the article, you linked, in the listing of the first .cpp file, at line 4 is:
#define DLL_EXPORT
This will insure that when this DLL is compiled, it will include this symbol defined and thus use:
#define DECLDIR __declspec(dllexport)
In the header file, which will also be included by client projects, there is no such definiation, and thus will use:
#define DECLDIR __declspec(dllimport)
This is the correct usage.
gcc (GCC) 4.7.2
Hello,
I am creating a shared library that will compile on linux and a dll that will compile on windows using the same source code. So i am creating an portable library for both linux and windows.
In my header file for the library is this i.e. module.h
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type
#else
#define LIB_INTERFACE(type) type
#endif
LIB_INTERFACE(int) module_init();
#ifdef __cplusplus
}
#endif
In the source I have the following i.e. module.c
#include "module.h"
LIB_INTERFACE(int) module_init()
{
/* do something useful
return 0;
}
And in my test application that will link and use this module.so I have this:
#include "module.h"
int main(void)
{
if(module_init() != 0) {
return -1;
}
return 0;
}
1) Is what I have done above is it a correct implementation of creating a portable library for linux and windows?
2) I am just wondering as I have wrapped the functions in extern "C" so that this library can been called from a program that has been compiled in C++. Do I still need this EXTERN_C in the following:
#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type
3) What is the purpose of the EXTERN_C?
Many thanks in advance,
This is a typical way to export a DLL API for Windows and still support Linux:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
# ifdef MODULE_API_EXPORTS
# define MODULE_API __declspec(dllexport)
# else
# define MODULE_API __declspec(dllimport)
# endif
#else
# define MODULE_API
#endif
MODULE_API int module_init();
#ifdef __cplusplus
}
#endif
In the DLL source:
#define MODULE_API_EXPORTS
#include "module.h"
MODULE_API int module_init()
{
/* do something useful */
return 0;
}
Your application source is correct.
Using the above model, on Windows the DLL will export the API while the application will import it. If not on Win32, the __declspec decoration is removed.
Since the header wraps the entire interface in extern "C", using the EXTERN_C macro on each interface is not required. extern "C" is used to tell the linker to use C linkage instead of C++. C linkage is standard across compilers, whereas C++ is not, limiting the use of a DLL to application built with the same compiler.
There is no need to integrate the return type into the API macro.
extern "C" basically means that you are telling the compiler not to mangle your function name.
Mangling is the process of "encoding" function names for later execution and is quite different in C and C++ as C++ can have different functions having the same name (via overloading etc...).
In C++ source, what is the effect of extern "C"?
Once compiled these functions can be called from anywhere but you might want to be sure what kind of library you are creating (static or dynamic) before you start.
Also I recommend you not using DEFINES like you do in the same file for portability purposes because of the maintenance or readability problems you might encounter later in the development.
I would create a basic file defining an interface which is fully portable to WIN and UNIX then create two other libraries implementing the interface but for different platforms.
For example you can have:
AbstractInterface.h, WinInterface.h, UnixInterface.h
Then only compile the ones you need depending on the platform.
For Linux, gcc without -fvisibility=hidden will make functions exported by default, except for static functions.
With -fvisibility=hidden, gcc will make no functions exported by default, except that functions decorated by
__attribute__ ((visibility ("default")))
For Windows, exported functions decorated by
__attribute__ ((dllexport))
when using the exported functions, they must be decorated by
__attribute__ ((dllimport))
The macros in your posts
__declspec(dllexport)
are supported by MSVC.
So the crossed linux and windows macros are as following:
#if defined _WIN32 || defined __CYGWIN__ || defined __MINGW32__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllexport))
#else
#define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllimport))
#else
#define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define DLL_LOCAL
#else
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif
Make sure that shared object or DLL projects must be compiled
with -DBUILDING_DLL.
The project that depends on your shared object or DLL must be compiled without -DBUILDING_DLL
For the more details, please read http://gcc.gnu.org/wiki/Visibility
Due to the concept of polymorphism which is specific to c++ language, All the functions defined in c++ are mangled. i.e., to create unique names for each overridden function, the "compiler" decorates the function names.
Since name mangling is handled by "compiler" and there is no specification to strictly define the name mangling rules, each compiler decorates the names in different ways. Simply put, gcc and msvc compilers create different function signatures for the same code. you can read further about name mangling at the wiki article here.
Your module.h file simply tells the compiler to use c style name mangling or no mangling at all. due to this directive, the library that is compiled by gcc can be used to link to a binary that is written in visual studio. This will help you to distribute the binaries of your library instead of source code.
On the other hand, if you do not use the EXTERN_C directive, the library and the project that links to the library should be compiled using same compiler. for example, you have to use gcc for linux compilation and msvc for windows compilation for both the library and the project linking to that library.
Instead of writing a header file yourself, you can also let CMake generate one for the building compiler using CMake's generate_export_header like this (examples taken from the linked page):
add_library(libfoo foo.cpp)
generate_export_header(libfoo)
#include "libfoo_export.h"
class LIBFOO_EXPORT FooClass {
int bar;
};
I am creating a c++ dll to be imported in vb.net.
I have found that the best way to organize the imports and exports in the header file of the dll, is something of the following type:
#ifndef MY_DLL_EXPORTS
#define MY_DLL_EXPORT __declspec(dllexport)
#else
#define MY_DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
MY_DLL_EXPORT BOOL my_function(uint32_t x);
#ifdef __cplusplus
}
#endif
My question is, where are the __cplusplus and MY_DLL_EXPORTS supposed to be defined ?
I have not done this before and I can't seem to find a place in the code for it. I read something about putting these definitions in the
Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Do I put them in the DLL's project properties ? and if i do, on using this DLL, will they always be defined so the if statement will always go to the dllimport ?
Also, is __cplusplus already defined or must I define it ?
__cplusplus is defined for you by a C++ compiler, but NOT by a C compiler. This is how you can determine if your code is being compiled by a C or C++ compiler. That's why this is used to guard the extern "C" construct. A C compiler would just omit it (since it emits C linkage already).
The other constants can be either defined on the compiler's command line (eg. in the menu you listed), or in the code somewhere:
#define MY_DLL_EXPORTS
Best place to define COMPILING_DLL is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
In my C++ header file, I have the following:
#ifdef _DLL
#define DLL_API __declspec(dllexport) // Being compiled as a DLL.
#else
#define DLL_API // Not being compiled as a DLL.
#endif
Later on, I have things like:
DLL_API int GetNumber();
I'm oversimplifying, but the basic question here is whether there's a way to get the compiler to just skip over DLL_API if it's not defined.
No.
When DLL_API is defined as preprocessor macro that contains nothing then preprocessor replaces DLL_API with nothing and compiler will see nothing there. If it is undefined for preprocessor then preprocessor does nothing with it. Then compiler will see it unchanged and you get compiler error about unknown identifier DLL_API, because such thing is not part of C++ language.
Attributes like __declspec() are platform specific extensions and it is common convention to wrap their usage in interfaces into preprocessor macros.
Usually, it is
#ifdef _WIN32
#ifdef _DLL
#define DLL_API __declspec(dllexport) // Being compiled as a DLL.
#else
#define DLL_API __declspec(dllimport) // Not being compiled as a DLL.
#endif
#else
#define DLL_API
#endif
so that it is portable, and DLL_API is always transformed into something valid.
Is there a Linux equivalent of __declspec(dllexport) notation for explicitly exporting a function from a shared library? For some reason with the toolchain I'm using, functions that aren't class members don't appear in the resulting shared library file.
__attribute__((visibility("default")))
And there is no equivalent of __declspec(dllimport) to my knowledge.
#if defined(_MSC_VER)
// Microsoft
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#elif defined(__GNUC__)
// GCC
#define EXPORT __attribute__((visibility("default")))
#define IMPORT
#else
// do nothing and hope for the best?
#define EXPORT
#define IMPORT
#pragma warning Unknown dynamic link import/export semantics.
#endif
Typical usage is to define a symbol like MY_LIB_PUBLIC conditionally define it as either EXPORT or IMPORT, based on if the library is currently being compiled or not:
#if MY_LIB_COMPILING
# define MY_LIB_PUBLIC EXPORT
#else
# define MY_LIB_PUBLIC IMPORT
#endif
To use this, you mark your functions and classes like this:
MY_LIB_PUBLIC void foo();
class MY_LIB_PUBLIC some_type
{
// ...
};