3

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)
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Casperscacion
  • 33
  • 1
  • 4
  • 1
    are you compiling for windows? `__declspec(dllexport)` has to do with the special linker semantics in windows (import libraries) and is non-existent on other systems. –  May 11 '17 at 14:58
  • Maybe this can help http://stackoverflow.com/questions/6721364/creating-a-dll-in-gcc-or-cygwin – Support Ukraine May 11 '17 at 15:02
  • 2
    Possible duplicate of [Creating a DLL in GCC or Cygwin?](http://stackoverflow.com/questions/6721364/creating-a-dll-in-gcc-or-cygwin) – KevinDTimm May 11 '17 at 15:12
  • I think you need to answer this question: Is your target output for Windows or Linux? Windows uses DLLs, whereas Linux (generally) uses SOs. You seem to be using Linux (Ubuntu), so are you really trying to target a different operating system (Windows), or are you trying to create a SO to use on Linux? – Neil May 11 '17 at 16:06
  • Yes, I was indeed compiling for Windows. Didn't realize I needed to cross compile. Thank you all. – Casperscacion May 12 '17 at 13:27

2 Answers2

6

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.

  • 1
    You seem to have missed the alternative that he is writing a DLL for Windows on Windows and using gcc with e.g. Cygwin. The answer for Cygwin btw is the same as your section 1 but without `-fPic` needed. – JeremyP May 11 '17 at 15:15
  • @JeremyP nope, the question clearly states `gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)` –  May 11 '17 at 15:16
  • OK didn't see that. – JeremyP May 11 '17 at 15:17
  • maybe it's the new windows 10 ubuntu subsystem ;) –  May 11 '17 at 15:18
  • I did hear that Microsoft are trialling a new kernel for Windows 11 that uses a core Linux kernel and a compatibility layer for the NT syscalls. – JeremyP May 11 '17 at 15:22
  • @FelixPalmen Thank you! Worked for me. I did not realize that I had to use mingw for that as all examples I looked up used __declspec and compiled with standard gcc. The extended dll example is also very helpful. – Casperscacion May 12 '17 at 13:25
  • @Casperscacion YW. To clarify, it's the usual convention that the compiler without a "host triplet" prefixed builds code for the same system it runs on, so if you're on linux, by invoking `gcc`, you build linux binaries, and on windows windows binaries. If you want to build windows binaries on linux, you need the prefixed version (cross compiler). –  May 12 '17 at 13:31
4

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.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • Thank you, this worked, but Felix answered first so I marked his answer. – Casperscacion May 12 '17 at 13:26
  • It is more detailed anyway and explores all probables. So yeah, I don't mind. – Ajay Brahmakshatriya May 12 '17 at 13:32
  • Still a good answer for the cross-compiling case, so upvoting here -- and I'm a little surprised, Ubuntu really calls the mingw variant of gcc `gcc-mingw32`? This doesn't meet the convention (`[target-triplet]-gcc`) :o –  May 13 '17 at 09:21