Trouble using scriptedmain in MinGW - gcc

I want to reproduce this Perl code in C, bundling API and CLI in the same C source code file (scriptedmain). This is done in Python with if __name__=="__main__": main() and in gcc/Unix, this looks like:
$ gcc -o scriptedmain scriptedmain.c scriptedmain.h
$ ./scriptedmain
Main: The meaning of life is 42
$ gcc -o test test.c scriptedmain.c scriptedmain.h
$ ./test
Test: The meaning of life is 42
scriptedmain.h
int meaning_of_life();
scriptedmain.c
#include <stdio.h>
int meaning_of_life() {
return 42;
}
int __attribute__((weak)) main() {
printf("Main: The meaning of life is %d\n", meaning_of_life());
return 0;
}
test.c
#include "scriptedmain.h"
#include <stdio.h>
extern int meaning_of_life();
int main() {
printf("Test: The meaning of life is %d\n", meaning_of_life());
return 0;
}
However, when I try to compile with gcc/Strawberry, I get:
C:\>gcc -o scriptedmain scriptedmain.c scriptedmain.h
c:/strawberry/c/bin/../lib/gcc/i686-w64-mingw32/4.4.3/../../../../i686-w64-mingw32/lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o): In function `main':
/opt/W64_156151-src.32/build-crt/../mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain#16'
collect2: ld returned 1 exit status
And when I try to compile with gcc/MinGW, I get:
$ gcc -o scriptedmain -mwindows scriptedmain.c scriptedmain.h
c:/mingw/bin/../lib/gcc/mingw32/4.5.2/../../../libmingw32.a(main.o):main.c:(.text+0x104): undefined reference to `WinMain#16'
collect2: ld returned 1 exit status
How can I get GCC in Windows to recognize the __attribute__((weak)) syntax?
Also, G++ shows the same error.

I found a solution that works in Windows and in Unix: Simply wrap main() in preprocessor instructions that omits it unless explicit compiler flags are set.
scriptedmain.c:
#include <stdio.h>
int meaning_of_life() {
return 42;
}
#ifdef SCRIPTEDMAIN
int main() {
printf("Main: The meaning of life is %d\n", meaning_of_life());
return 0;
}
#endif
Now main() will be entirely omitted unless you compile with
gcc -o scriptedmain -DSCRIPTEDMAIN scriptedmain.c scriptedmain.h
This code is safe to import into other C code, because the preprocessor will strip out main(), leaving you to code your own main. The best part is that this solution no longer depends on obscure compiler macros, only simple preprocessor instructions. This solution works for C++ as well.

This isn't good practice in C regardless of operating system. Best practice in C for anything complicated enough to be worth separating into library and driver is to put main in a file all by itself.

Related

Error while building a static Linux binary (with musl-libc) that includes LuaJIT

I've cloned the LuaJIT git repo and built it with:
make STATIC_CC="musl-gcc" BUILDMODE="static"
Then, I compiled a simple Lua "hello world" script into a C header file:
luajit -b test.lua test.h
test.h:
#define luaJIT_BC_test_SIZE 52
static const unsigned char luaJIT_BC_test[] = {
27,76,74,2,10,45,2,0,3,0,2,0,4,54,0,0,0,39,2,1,0,66,0,2,1,75,0,1,0,20,72,101,
108,108,111,32,102,114,111,109,32,76,117,97,33,10,112,114,105,110,116,0
};
After that, I wrote a simple C wrapper by following the official example, test.c:
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "test.h"
int main(void) {
int error;
lua_State *L = lua_open();
luaL_openlibs(L);
error = luaL_loadbuffer(L, (const char *) luaJIT_BC_test, luaJIT_BC_test_SIZE, "test") || lua_pcall(L, 0, 0, 0);
if (error) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
return 0;
}
But when I try to build it, it crashes with an error:
$ musl-gcc -static -ILuaJIT/src -LLuaJIT/src -o test test.c -lluajit
/usr/bin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/12.1.0/libgcc_eh.a(unwind-dw2-fde-dip.o): in function `_Unwind_Find_FDE':
(.text+0x1953): undefined reference to `_dl_find_object'
collect2: error: ld returned 1 exit status
It's related to libgcc, so I tried building everything with musl-clang, but still got the same error. Can someone explain what I'm missing here?
Figured it out - I needed to build LuaJIT with TARGET_XCFLAGS=-DLUAJIT_NO_UNWIND like so:
make STATIC_CC="musl-gcc" BUILDMODE="static" TARGET_XCFLAGS=-DLUAJIT_NO_UNWIND
I guess this just disables C++ exceptions support, but I'm not sure what the real implications are. Seems to work fine, for now.

Weird C library linkage issues on Mac - Segmentation Fault

I have a strange segmentation fault that doesn't exist when everything is in 1 .c file, but does exist when I put part of the code in a dynamically linked library and link it to a test file. The complete code for the working 1 .c file code is at the bottom, the complete code for the error system with 2 .c and 1 .h file come first.
Here is the error system:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c:
This is essentially a test file:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
Makefile:
I link example to example2 here, and run:
example:
#clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
#clang example2.c example.dylib -o example2.o
#./example2.o
.PHONY: example
The output is:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
But it should show the full output of:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
The weird thing is everything works if it is this system:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
Makefile:
example:
#clang -o example example.c
#./example
.PHONY: example
Wondering why it's creating a segmentation fault when it is linked like this, and what I am doing wrong.
I have checked otool and with DYLD_PRINT_LIBRARIES=YES and it shows it is importing the dynamically linked libraries, but for some reason it's segmentation faulting when linked but works fine when it isn't linked.
Your problem is this, in example.h:
MYARRAY *collection;
Since both main.c and example.c include this file, you end up defining collection twice, which results in undefined behavior. You need to make sure you define each object only once. The details are relatively unimportant since anything can happen with undefined behavior, but what's probably happening is that main.c is allocating memory for one object, but the one example.c is using is still NULL. As mentioned in the comments, since you define collection in main.c your linker is able to build the executable without needing to look for that symbol in the dynamic library, so you don't get a link time warning about it being defined there too, and obviously there'd be no cause for a warning at the time you compile the library.
It works for you when you put everything in one file because obviously then you're not defining anything twice, anymore. The error itself is nothing to do with the fact you're using a dynamic library, although that may have made it harder to detect.
It would be better to define this in example.c and provide a constructor function, there's no need for main() to be able to access it directly. But if you must do this, then define it in example.c and just declare an extern identifier in the header file to tell main.c that the object is defined somewhere else.

Strange behavior with gcc and inline

I want to define an inline function in a header file (.h) which can be included by numerous source files (.c). Here is a minimal example with 1 header and 2 source files:
Header file foo.h
int ifunc(int i);
extern inline
int
ifunc(int i)
{
return i + 1;
}
Source code file: foo.c
#include <stdio.h>
#include "foo.h"
int foo2(int i);
int main()
{
printf("%d\n", foo2(1));
return 0;
}
Source code file foo2.c
#include "foo.h"
int foo2(int i)
{
return ifunc(i);
}
The problem
When I compile with optimization,
gcc -g -Wall -O2 -o foo foo.c foo2.c
$ ./foo
2
everything works fine. However when I turn off optimization, I get this error:
gcc -g -Wall -o foo foo.c foo2.c
/tmp/cc3OrhO9.o: In function `foo2':
foo2.c:5: undefined reference to `ifunc'
Can someone please explain how to fix so that I can run the code with and without -O2? I am using gcc 4.8.5.
if you replace foo.h with
static inline int ifunc(int i)
{
return i + 1;
}
Both will work.
Declaring it extern means it'll be defined somewhere else which in your original example does not happen. And the optimized build doesn't flag as an error because it already optimized it to be inline it but the non-optimized build does not find a definition in any of the .o files (since they were all compiled with ifunc being an extern as defined in foo.h).
Declaring as static inline will ensure that it is local to each file (the downside being that if it does not inline it, you'll end up with each .o that needs it having a local copy, so don't overdo it).

Undefined function from static library

I am trying to build a static library using MinGW.
Everything was going fine until I tried to use the library and got an error saying that add_numbers is an undefined function.
Many other people have had this problem and sorted it out by moving their library to be linked after the source files were included, but that was how I had written my batch file anyway, so that was not of much help.
Here are my sources.
mylib.h
#ifndef MYLIB_H
#define MYLIB_H
int add_numbers(int a, int b, int c);
#endif
mylib.c
#include "mylib.h"
int add_numbers(int a, int b, int c)
{
return a+b+c;
}
I'm building my .a file with the following commands
gcc --std=c89 -c mylib.c -o mylib.o
ar rcs libmylib.a mylib.o
I've also tried with out specifying the standard.
There are no errors or warnings when running this command.
Next, my test program looks like this.
#include <stdio.h>
#include "mylib.h"
int main()
{
printf("The sum of 1, 2, and 3 is %d", add_numbers(1, 2, 3));
getchar();
return 0;
}
And lastly, we build the test with this command.
gcc mylibtest.c -L -lmylib -o test.exe
I've tried moving around those commands into many many different sequences, but always receiving the following error:
C:\Users\Aaron\AppData\Local\Temp\cc0ERpBi.o:mylibtest.c:(.text+0x26): undefined
reference to `add_numbers'
collect2.exe: error: ld returned 1 exit status
E:\my_first_static_library>
Any help would be very appreciated, I've read every tutorial I could find on the art of writing static libraries, as well as a good ten stackoverflow questions.
You are missing a dot after -L:
gcc mylibtest.c -L . -lmylib -o test.exe

gfortran multiple definition of main

I'm having trouble with compiling a piece of code I have been given for my research. It consists of one component written in C++ and the other in FORTRAN. I think the problem is to do with my gcc version.
The first file for example is a C++ file (foo.ccp)
#include <iostream>
using namespace std;
extern "C" {
extern int MAIN__();
}
int main(){
cout << "main in C++\n";
return MAIN__();
}
The second is bar.f90:
program test
implicit none
print*, 'MAIN in FORTRAN'
end program test
I'm trying to compile it like so:
g++ -c foo.cpp
gfortran foo.o -lstdc++ bar.f90
It compiles fine with GCC-4.4.7 but fails with GCC-4.8.x with the error reading:
/tmp/cc5xIAFq.o: In function `main':
bar.f90:(.text+0x6d): multiple definition of `main'
foo.o:foo.cpp:(.text+0x0): first defined here
foo.o: In function `main':
foo.cpp:(.text+0x14): undefined reference to `MAIN__'
collect2: error: ld returned 1 exit status
I've read here that there's a change in how gfortran handles naming of the 'main' and 'MAIN__' functions since version 4.5.x but I'm not sure how to fix my problem.
Any ideas as to what I'm missing? Thanks for your help!
You have two main symbols:
int main(){
cout << "main in C++\n";
return MAIN__();
}
and
program test
implicit none
print*, 'MAIN in FORTRAN'
end program test
The main program is given the symbol main. You cannot link these two programs together because the two main symbols conflict. You also have the issue that since the Fortran program is given the main symbol and not MAIN__ that symbol is undefined. Your goal is to call Fortran from C++, you should do this:
#include <iostream>
extern "C" {
int FortMain();
}
int main()
{
std::cout << "main in C++\n";
return FortMain();
}
and
function FortMain() bind(C,name="FortMain")
use iso_c_binding
implicit none
integer(c_int) :: FortMain
print *, "FortMain"
FortMain = 0
end function FortMain
These will compile and link together and do what your code is attempting to do. These make use of Fortran's iso_c_binding features to ensure the Fortran function is fully interoperable with C with proper case and no underscoring funny business. The Fortran function also returns a value so matches the C prototype your have provided in your example.

Resources