Trying to compile simple dll written in C using gcc fails - c

Trying to compile a simple DLL written in C using gcc.
Tried following many tutorials, but can't get it to compile even when I strip the file down to the very basics.
test_dll.c
#include <stdio.h>
__declspec(dllexport) int __stdcall hello() {
printf ("Hello World!\n");
}
Trying to compile this using the command
gcc -c test_dll.c
Failing, getting this output
test_dll.c: In function '__declspec':
test_dll.c:3:37: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'hello'
__declspec(dllexport) int __stdcall hello() {
^
test_dll.c:5:1: error: expected '{' at end of input
}
^
gcc version
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

It depends on what you're trying to do:
1. build a library for linux on linux
then remove the __declspec(dllexport) and __stdcall. On linux, you need nothing special in the source code for building a library. Note that libraries aren't DLLs on linux, they're named *.so (shared object). You'll have to compile with -fPIC and link with -shared to create your .so file. Please use google for more details on this.
2. build a windows DLL on linux
Install mingw packages (search for them in your package manager). Then, instead of just gcc, invoke the cross compiler targeting windows/mingw, e.g. i686-w64-mingw32-gcc.
3. allow to build libraries cross-platform, including windows
If you want to be able to build a library from the same code on windows and linux, you'll need some preprocessor magic for this, so __declespec() is only used when targeting windows. I normally use something like this:
#undef my___cdecl
#undef SOEXPORT
#undef SOLOCAL
#undef DECLEXPORT
#ifdef __cplusplus
# define my___cdecl extern "C"
#else
# define my___cdecl
#endif
#ifndef __GNUC__
# define __attribute__(x)
#endif
#ifdef _WIN32
# define SOEXPORT my___cdecl __declspec(dllexport)
# define SOLOCAL
#else
# define DECLEXPORT my___cdecl
# if __GNUC__ >= 4
# define SOEXPORT my___cdecl __attribute__((visibility("default")))
# define SOLOCAL __attribute__((visibility("hidden")))
# else
# define SOEXPORT my___cdecl
# define SOLOCAL
# endif
#endif
#ifdef _WIN32
# undef DECLEXPORT
# ifdef BUILDING_MYLIB
# define DECLEXPORT __declspec(dllexport)
# else
# ifdef MYLIB_STATIC
# define DECLEXPORT my___cdecl
# else
# define DECLEXPORT my___cdecl __declspec(dllimport)
# endif
# endif
#endif
Then put a DECLEXPORT in front of each declaration to be exported by the lib and SOEXPORT in front of each definition. That's just a quick example.

Since you are compiling on Linux, the gcc takes Linux as the target.
What you want to do is cross compile for Windows. Which means you will need a cross compiler. The one available for Ubuntu Linux is mingw.
You can install it using
apt-get install gcc-mingw32
Then you can compile with
gcc-mingw32 -c test_dll.c
Further compiling into dll would need
gcc-mingw32 --shared test_dll.o -o test_dll.dll
This dll can then be used on Windows.

Related

How can I compile a criterion test using cmake and mingw on linux?

I have been trying to compile a small test on linux using cmake and mingw.
However, the criterion.h library does not get linked when I cross-compile (regular compiling works fine).
The toolchain file specifies mingw as the compiler. But I do not know how to make it link the criterion.h file.
When I do cmake --build ., I get the error test_stock_api.c:4:10: fatal error: criterion/criterion.h: No such file or directory.
Test code
// test_stock_api.c
#include <criterion/criterion.h>
#include <string.h>
#include "../src/stock.h"
Test(u_stock_api, set_tiingo_api) {
set_tiingo_api("new_api_key");
cr_assert(strcmp(TIINGO_API_KEY, "new_api_key") == 0, \
"Tiingo api key could not be set.");
}
CMakeLists file
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(stocklib)
add_library(stock STATIC src/stock.c)
include(CTest)
#set(CMAKE_CROSSCOMPILING true)
set(CMAKE_EXE_LINKER_FLAGS "-static" "-rpath-link")
# single test setup
add_executable(test_stock_api tests/test_stock_api.c)
target_link_libraries(test_stock_api -lcriterion)
target_link_libraries(test_stock_api stock)
add_test(
NAME test_stock_api
COMMAND $<TARGET_FILE:test_stock_api>
)
Toolchain file
# cmake cross-compiling toolchain file
set(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
# here is the target environment located
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 /usr/include /usr/local)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)

gcc compile with 32-bit architecture not working

I am trying to compile a C file with gcc. The code in header file will need specified architecture in order to compile.
#if defined( _8BIT_ARCHITECTURE )
#include "type8.h"
#elif defined( _16BIT_ARCHITECTURE )
#include "type16.h"
#elif defined( _32BIT_ARCHITECTURE )
#include "type32.h"
#else
#error ARCHITECTURE not defined
#endif
When using Visual Studio, I can configure the platform into 32-bit and it can build successfully. But how do I do the same thing with gcc commands?
I was trying to use:
gcc -m32 -c myFile.c -I /somePath/
But it keeps giving me the error statement:
#error ARCHITECTURE not defined
Adding -D_32BIT_ARCHITECTURE fix the issue

How can I tell i'm compiling on a mac?

I'm using a compiled-from-source gcc for the avr. My gcc configure options are:
${PWD}/../gcc/configure --prefix="${PWD}/../build/" --exec-prefix="${PWD}/../build/" --datadir="${PWD}/../build/" --target=avr --enable-languages=c --disable-libssp --disable-lto --disable-nls --disable-libgomp --disable-gdbtk --disable-threads --enable-poison-system-directories
When I use the following snippet of preprocessor magic
#if defined __APPLE__
#error "Apple"
#else
#error "Ahh"
#endif
it is outputting
error: #error "Ahh"
If I run avr-cpp -dM version.h I see __APPLE__ is not defined. If I run cpp -dM version.h I see that __APPLE__ is defined. What do I have to change in my configure line (or elsewhere) to get my compiled-from-source gcc to have __APPLE__ defined correctly?
I'm on a mac compiling for the avr as apposed to being on windows compiling for the avr.
Probably all you can potentially need is HERE
and specifically about Mac here

Is there a way to list all C preprocessor defines?

Is there a way to list all C preprocessor defines?
I'm on a mac with a compiled from source gcc and
#if defined __APPLE__
#error "Apple"
#else
#error "Ahh"
#endif
is giving me:
error: #error "Ahh"
my compile configure options are:
${PWD}/../gcc/configure --prefix="${PWD}/../build/" --exec-prefix="${PWD}/../build/" --datadir="${PWD}/../build/" --target=avr --enable-languages=c --disable-libssp --disable-lto --disable-nls --disable-libgomp --disable-gdbtk --disable-threads --enable-poison-system-directories
If you are using gnu cpp, you can pass the option -dM to emit all defined macros. That is:
$ cpp -dM foo.c
will tell you everything that is defined for foo.c. There will be extra defines passed on the command line by make, and probably more things in config.h, but if you grab the output of make and rerun the commands with -Xpreprocessor -dM added you should see everything.

C-library not linking using gcc/g++

I have a c-library which I use in gcc. The library has the extension .lib but is always linked as a static library. If i write a program which uses the library as c-code, everything as a-ok. If I however rename the file to .cpp (doing simple stuff that works in both c/c++) I get undefined reference. These are simple small programs I write for testing purposes so no fancy stuff. I compile using:
gcc -g -Wall -I <path to custom headers> -o program main.c customlibrary.lib -lm -lpthread
The above works like a charm. However:
g++ -g -Wall -I <path to custom headers> -o program main.cpp customlibrary.lib -lm -lpthread
or
gcc -g -Wall -I <path to custom headers> -o program main.cpp customlibrary.lib -lm -lpthread -lstdc++
results in undefined reference to any function in customlibrary.lib. I tried creating a symbolic link named customlibrary.a but no luck.
Why won't g++ find recognize my library. Unfortunately I have no access to the source code of the libraries but linking a c-lib to c++ should not be a problem right?
Your library appears to have an API that assumes it will be called from C, not C++. This is important because C++ effectively requires that the symbols exported from a library have more information in them than just the function name. This is handled by "name mangling" the functions.
I assume your library has an include file that declares its public interface. To make it compatible with both C and C++, you should arrange to tell a C++ compiler that the functions it declares should be assumed to use C's linkage and naming.
A likely easy answer to test this is to do this:
extern "C" {
#include "customlibrary.h"
}
in your main.cpp instead of just including customlibrary.h directly.
To make the header itself work in both languages and correctly declare its functions as C-like to C++, put the following near the top of the header file:
#ifdef __cplusplus
extern "C" {
#endif
and the following near the bottom:
#ifdef __cplusplus
}
#endif
The C++ compiler performs what is known as name-mangling - the names that appear in your code are not the same ones as your linker sees. The normal way round this is to tell the compiler that certain functions need C linkage:
// myfile.cpp
extern "C" int libfun(); // C function in your library
or do it for a whole header file:
// myfile.cpp
extern "C" {
#include "mylibdefs.h" // defs for your C library functions
}
Does your header file have the usual
#ifdef __cplusplus
extern "C" {
#endif
// ...
#ifdef __cplusplus
} /* extern "C" */
#endif
to give the library functions C linkage explicitly.
.cpp files are compiled with C++ linkage i.e. name mangling by default.

Resources