How to let MinGW compiled program link to dll built by cygwin? - c

My program uses some libraries which contains POSIX function calls and cannot be compiled with MinGW, and I use Qt6 for MinGW (no Qt6 for cygwin or msys2). So I need to make my program link to the dll built by cygwin. It linked successfully, but it cannot run.
For example, here are two files a.c and b.c:
/* a.c */
int a() {
return 1;
}
/* b.c */
extern int a();
int main() {
return a();
}
I compiled a.c to a.dll using cygwin:
(In cygwin shell)
$ gcc -c a.c -o a.o
$ gcc -shared a.o -o a.dll
$ ldd a.dll
ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x7ff9d5450000)
KERNEL32.DLL => /cygdrive/c/Windows/System32/KERNEL32.DLL (0x7ff9d50f0000)
KERNELBASE.dll => /cygdrive/c/Windows/System32/KERNELBASE.dll (0x7ff9d2e90000)
msvcrt.dll => /cygdrive/c/Windows/System32/msvcrt.dll (0x7ff9d5370000)
cygwin1.dll => /cygdrive/c/Users/notify/Documents/cygwin1.dll (0x180040000)
advapi32.dll => /cygdrive/c/Windows/System32/advapi32.dll (0x7ff9d3b70000)
sechost.dll => /cygdrive/c/Windows/System32/sechost.dll (0x7ff9d3c20000)
RPCRT4.dll => /cygdrive/c/Windows/System32/RPCRT4.dll (0x7ff9d51b0000)
CRYPTBASE.DLL => /cygdrive/c/Windows/SYSTEM32/CRYPTBASE.DLL (0x7ff9d2440000)
bcryptPrimitives.dll => /cygdrive/c/Windows/System32/bcryptPrimitives.dll (0x7ff9d2b50000)
Then I compiled b.c using MinGW and link it to a.dll:
(In MSYS2 MINGW64 shell)
$ gcc -c b.c -o b.o
$ gcc b.o -L. a.dll -o b.exe
$ ldd b.exe
ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ff9d5450000)
KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ff9d50f0000)
KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ff9d2e90000)
msvcrt.dll => /c/Windows/System32/msvcrt.dll (0x7ff9d5370000)
a.dll => /c/Users/notify/Documents/a.dll (0x5e4da0000)
cygwin1.dll => /c/Users/notify/Documents/cygwin1.dll (0x180040000)
$ ./b.exe
0 [main] b (1828) C:\Users\notify\Documents\b.exe: *** fatal error - cygheap base mismatch det
ected - 0x180350408/0x18034C408.
This problem is probably due to using incompatible versions of the cygwin DLL.
Search for cygwin1.dll using the Windows Start->Find/Search facility
and delete all but the most recent version. The most recent version *should*
reside in x:\cygwin\bin, where 'x' is the drive on which you have
installed the cygwin distribution. Rebooting is also suggested if you
are unable to find another cygwin DLL.
How can I solve this problem?

Answer
Don't mix MinGW and Cygwin binaries!
In fact you should treat them as different patforms:
MinGW / MinGW-w64 targets native Windows
Cygwin doesn't target native Windows, but instead uses a POSIX compatibility layer.
Their standard libraries are different and incompatible with each other.
This also goes for MSVC, so also don't mix MinGW / MinGW-w64 or Cygwin with MSVC.
Solution
Compile all components and dependencies of your project with the same compiler.
Some tips
Prefer MinGW-w64
It's best to use MinGW / MinGW-w64 where possible as this targets native Windows.
Arguments:
Cygwin build will require redistribution of Cygwin DLL(s) along with your application, when you want to make it available for other systems or people.
The Cygwin compatibility layer may cause overhead so your application may be less performant than when build with MinGW / MinGW-w64
Finally: MinGW-w64 is more up to date than MinGW so you should MinGW-w64 instead of MinGW. MinGW-w64 supports both 32-bit and 64-bit Windows. You can install MinGW-w64 via MSYS2's package manager pacman, or you can get a standalone build from https://winlibs.com/
POSIX functions missing in MinGW / MinGW-w64
A downside of using MinGW / MinGW-w64 is that some POSIX functions are missing (e.g. fork()).
So you need to replace those with their Windows alternatives.
In case of fork() where it is used to spawn a daemon process you may need to redesign that peace of code a bit more than finding an alternative for fork() since Windows doesn't use deamons but services. So you need to write some Windows specific code for Windows to allow your application to run as a Windows service. You can use #ifdef _WIN32 to still keep your POSIX code in your application so it will still compile on POSIX platforms.
For some POSIX functions there are already some libraries out there providing Windows alternatives with a compatible C header, for example:
dlfcn.h: https://github.com/dlfcn-win32/dlfcn-win32
sys/mman.h/mmap()/munmap(): https://github.com/alitrack/mman-win32
fork(): https://github.com/i-e-b/win32-fork

Related

Why gcc under Windows O.S. produces a .o instead of a .lib file when compiling static libraries?

I am using gcc 8.1.0 on Windows. To install it I set up Code::Blocks on my computer and updated the environment variable list by adding the path to the gcc.exe program within the installation folder of CodeBlocks. The file editor I used was the built-in editor in Visual Studio. The terminal to compile was the power shell from Visual Studio as well.
In the library development folder I have the files mul.c and mul.h. Their content is irrelevant.
To compile the library I use the command:
gcc -c mul.c
When I run it, it creates a file object mul.o and not mul.lib. I needed to use the option -o mul.lib to successfully create the desired extension file. After placing the header, the .lib file and the main.c in the same parent folder I am obvioudly able to build the executable by running.
gcc main.c -I./include -L/static -lmul -o my_program.exe
I have two questions:
Why does gcc produces a .o if I am in a Windows environment?
I followed a tutorial that compile the static library under Linux and it names it libmul.o, in this way the -lmul option is able to retrieve the library. But if I call my generated static library libul.lib it generates the error:
C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/x86_64-w64-ingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmul
collect2.exe: error: ld returned 1 exit status
Are these a normal behaviours by gcc, or is it side effect of making gcc available just by updating the Windows environmental variables list?
Thank you to the community in advance.
GCC comes from the *nix world where libraries have the .a extension. When using GCC+MinGW this remains the case.
Shared libraries in MinGW are .dll files but their libraries for linking are .dll.a files.
The advantage of .a files is that a lot of sources build out of the box on Windows with MinGW, especially when using MSYS2 shell.
If you use -l it will look for .a (or .dll.a for shared build) file adding the lib prefix and the extension automatically.
So -lmul will look for libmul.a (static, e.g. when --static linker flag is given) or libmul.dll.a (shared).
By the way, you are using quite an old GCC 8.1.0.
As I write this current version is 12.2.0. Check https://winlibs.com/ for a standalone download (instructions on how to configure in Code::Blocks are on the site) or use MSYS2's package manager pacman.

memmem() in Mingw-w64 gcc

I'm trying to build a C program with Windows gcc using Mingw-w64 installation (gcc.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0).
I get undefined reference to `memmem' error. Isn't memmem() a standard glibc function that should be available in all gcc versions?
As this post explains
"MinGW does not build against glibc, it builds against msvcrt. As
such, it uses libmsvcrtXX.a instead." "gcc and glibc are two separate
products."
So, yep, no memmem on Windows and here's the implementation.

How to create an executable C file for Windows

I know this question has been asked several times and I took a look at many of them like
Running linux gcc-compiled program under windows
How can I compile C files into an executable (.exe) file?
Unfortunately, none of them worked for me.
My situation
I've installed Ubuntu and Windows on my Notebook.
Let's say I developed a simple "Hello,World!"program using a text editor in c.
In Ubuntu, I've compiled it using GCC
$ gcc -o hello.out -g -Wall -pedantic hello.c
I executed it './output.out'
And got the result Hello, World!
What I tried
So I kind of cross-developed here. I switched to Windows and kept going.
Now, I try to make it an executable file in order to run it on Windows. I know Windows can't handle '$ ./output.out' , alright, let's make it an executable then.
Under Windows, I've
installed cygwin
In Cygwin, I compiled it using GCC
$ gcc -o hello.exe -g -Wall -pedantic hello.c
Note: I wrote hello.exe instead of hello.out or hello.c
In Cygwin, I executed it '$ ./output.exe'
And got the result Hello, World!
Note: At this point, it even works with my Shell under Windows because I installed Cygwin and set up my PATH etc. This means I can open my command line, go to the directory in which 'hello.exe' is located and execute it by typing '> hello.exe'
I thought that would be it, so I took hello.exe' and moved it to another notebook (not my local machine). I tried to execute it but it didn't work.
At first, I got an cygwin1.dll missing message. After fixing it, another error appears.
What I'm trying to accomplish
To make a long story short:
The reason I wrote so much is that I want to give you a detailed look of my situation.
Basically, I'm trying to create an executable c file, which any Windows User could execute without having any development tools.
In Eclipse and Java, you could simply export your program making it a runnable -jar file. All the User has to do is install the latest Java SE version to get it running.
Additionally, I tried to compile my program in Visual Studio but that didn't work either.
Any suggestions? Thanks a lot!
cygwin gcc produce an executable linked to the cygwin1.dll. So it is not usable without that.
gcc hello.c -o hello-cygwin.exe
$ ldd hello-cygwin.exe
ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x77bd0000)
kernel32.dll => /cygdrive/c/Windows/system32/kernel32.dll (0x77ab0000)
KERNELBASE.dll => /cygdrive/c/Windows/system32/KERNELBASE.dll (0x7fefdc60000)
SYSFER.DLL => /cygdrive/c/Windows/System32/SYSFER.DLL (0x75650000)
cygwin1.dll => /usr/bin/cygwin1.dll (0x180040000)
If you need a standalone program, a solution is to use the mingw compiler
(it is available on cygwin as cross compiler to windows)
$ x86_64-w64-mingw32-gcc.exe hello.c -o hello-mingw64.exe
$ ldd hello-mingw64.exe
ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x77bd0000)
kernel32.dll => /cygdrive/c/Windows/system32/kernel32.dll (0x77ab0000)
KERNELBASE.dll => /cygdrive/c/Windows/system32/KERNELBASE.dll (0x7fefdc60000)
SYSFER.DLL => /cygdrive/c/Windows/System32/SYSFER.DLL (0x75650000)
msvcrt.dll => /cygdrive/c/Windows/system32/msvcrt.dll (0x7fefdf40000)
You can move the resulting program on another windows machine that don't have cygwin installed.
You should use mingw which is the gcc port for windows instead of gcc under cygwin. You can get it here.

Compiling 64-bit GSL on Cygwin using 64-bit GCC

I am trying to compile 64-bit GSL on a Windows 7 machine. Here are the steps I took:
Downloaded and untarred the GSL 1.15 source found here.
Tested that I have a 64-bit version of GCC available in the Cygwin shell, by compiling the minimal program
// simple.C
int main() {
;
return 0;
}
using
x86_64-w64-mingw32-gcc -m64 simple.C -o simple
In the untarred folder, I would like to pass the x86_64-w64-mingw32-gcc compiler to ./configure but am not sure how. I took a look at the configure file, but that is huge and appears to have been generated using autoconf.
At the cygwin prompt you can use:
CC=x86_64-w64-mingw32-gcc CFLAGS=-m64 ./configure
and configure will pick it up.
Important Note:
I am surprised that you don't have a wrapper gcc ... Why don't you try using ./configure by itself just as is to begin with and see what it does before overriding the C compiler as I showed.

How can I mimic the GNU/linux C development environment on OSX Lion?

I just tried to write a simple C program on OSX Lion
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
Compiling with gcc
$ gcc hello.c
test.c:1:19: error: stdio.h: No such file or directory
test.c: In function ‘main’:
test.c:3: warning: incompatible implicit declaration of built-in function ‘printf’
Ok...fine
$ gcc -I /Developer/SDKs/MacOSX10.6.sdk/usr/include
ld: library not found for -lcrt1.10.6.o
collect2: ld returned 1 exit status
What? Let's see...
$ gcc -I /Developer/SDKs/MacOSX10.6.sdk/usr/include -L/Developer/SDKs/MacOSX10.6.sdk/usr/lib test.c
$ ./a.out
hello world
Finally!
That seems like a lot of effort just to get a hello world working, how do I make gcc find libraries and header files in the MacOSX10.6.sdk directory by default like it does on linux? On linux I find ldd and ldconfig quite useful, they don't seem to exist on OSX...is there an equivalent? What other useful tools are there for developing C on OSX?
Yes, I know xcode makes this easier, but suppose I wanted to use vim and the command line to work on an opensource c project.
I can think of three possibilities:
You had 10.6 installed and upgraded to 10.7. You need to install the new version of Xcode (4.1, get it from the app store) to get back the developer tools.
you installed Xcode, did a custom install, and unchecked "UNIX development" or something. Rerun the installer and install the missing parts.
You installed a broken third-party version of gcc. Try which gcc and see what you get.
On OS X 10.7, if you have downloaded Xcode 4.1 from the Mac App Store and then run the installer that it downloads (in /Applications), your first attempt should have worked just fine assuming you have not set some environment variables that are looked at and influence Apple's gcc tool chain. The object file that is produced in this case would be using the default 10.7 ABI (include files and libs). If you want to produce something that would be compatible with OS X 10.6, then you need to tell the tool chain to use the 10.6 SDK ABI, which is what you did in the third attempt. A standalone project typically handles this by setting up a Makefile to automate building. But, unless you are trying to build something on a version of OS X (10.7 here) that will also run on earlier versions of OS X (say 10.6), there is generally no need to use an SDK.

Resources