The GMP docs say that static linking may provide a small performance improvement.
I am having a problem getting it to staticly link libgmp on my Linux systems. I've narrowed down the issue I'm having to a tiny test case.
gmptest.c
#include <gmp.h>
int main(int argc, char** argv) {
mpz_t foo;
mpz_init(foo);
return 0;
}
Makefile:
all: clean gmptest static
clean:
rm -f *.s
rm -f *.o
rm -f gmptest
rm -f static-gmptest
gmptest: Makefile gmptest.c
gcc -std=c99 -O3 -lgmp gmptest.c -o gmptest
static: clean Makefile gmptest.c
gcc -std=c99 -O3 -static /usr/lib/libgmp.a gmptest.c -o static-gmptest
The non-static binary is compiled and linked without any issues, but 'Make static' produces:
gcc -std=c99 -O3 -static /usr/lib/libgmp.a gmptest.c -o static-gmptest
/tmp/ccWSFke9.o: In function `main':
gmptest.c:(.text+0x8): undefined reference to `__gmpz_init'
collect2: ld returned 1 exit status
make: *** [static] Error 1
The library does exist:
chris#vostro:~/Dropbox/static$ ls -lA /usr/lib/libgmp.a
-rw-r--r-- 1 root root 1041666 2010-02-26 13:20 /usr/lib/libgmp.a
I have also tried -lgmp for the static linking, but the error is the same.
This is all on Ubuntu 10.04 and 10.10 AMD64.
Can some enlighten me as to the obvious error I'm making?
Thanks,
Chris.
Try
gcc -std=c99 -O3 -static gmptest.c -lgmp -o static-gmptest
since libraries should always be linked in the good order, and after the program or object files using them.
Here, in GMP 6.1.2 / MINGW and assuming certain portability, I find that the header "gmp.h" has fix link mode, as configured with GMP build parameters.
/* Instantiated by configure. */
#if ! defined (__GMP_WITHIN_CONFIGURE)
#define _LONG_LONG_LIMB 1
#define __GMP_LIBGMP_DLL 0
#endif
As with this the compiler will never generate static object decorations, and so the linker will never match the static libgmp, I conditioned the define __GMP_LIBGMP_DLL
/* Added link switch GMP_STATIC */
#if ! defined (__GMP_WITHIN_CONFIGURE)
#define _LONG_LONG_LIMB 1
#ifndef GMP_STATIC // SGR 2021-12-30
#define __GMP_LIBGMP_DLL 1
#endif
#endif
Now, with defined GMP_STATIC the static libgmp.a is successfully attracted and without GMP_STATIC the dynamic libgmp.dll.a.
Related
I am porting a project written in C from a CentOS 7 (Core) to an Ubuntu 20.04.1 LTS (Focal Fossa) system. The project relies heavily on the <cpuset.h> library, and compiles and executes correctly on the CentOS system. However, when I try to use functions from cpuset.h on the Ubuntu system, I get 'undefined reference' errors.
The following code, stored in file test.c, compiles and runs correctly on CentOS:
#define _GNU_SOURCE
#include<stdio.h>
#include <cpuset.h>
int main(){
int x = cpuset_version();
printf("cpuset lib version: %d\n",x );
return 0;
}
How I compile:
gcc -Wall -O2 -std=gnu99 -g -lcpuset test.c -o test
Output:
[xxxx#CentOS]$ ./test
cpuset lib version: 3
However, when I try to compile the same test.c file on the Ubuntu system, I get this error:
xxxx#Ubuntu:$ gcc -Wall -O2 -std=gnu99 -g -lcpuset test.c -o test
/usr/bin/ld: /tmp/ccpxlk4F.o: in function `main':
test.c:8: undefined reference to `cpuset_version'
collect2: error: ld returned 1 exit status
Furthermore, this is not limited to the <cpuset.h> library. I tried to use a simple function from <pthread.h> and it also gave me the same error. Can anyone help with identifying why I cannot use shared libraries on the Ubuntu system? Thanks in advance
Since OP's issue is wrong order of parameters to GCC (many guides do show an incorrect order!), as discussed in the comments to the question, I believe showing a minimal Makefile to handle these is warranted:
CC := gcc
CFLAGS := -Wall -O2 -g
LDFLAGS := -lcpuset
TARGETS := test
.PHONY: all clean
all: $(TARGETS)
clean:
rm -f *.o $(TARGETS)
%.o: %.c
$(CC) $(CFLAGS) -c $^
test: test.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Note that the indentation in Makefiles must use Tabs and not spaces. Since this forum converts Tabs to spaces, you will need to fix the above makefile, for example by running sed -e 's|^ *|\t|' -i Makefile.
If you want to compile say foo.c directly to an executable, the recipe is
foo: foo.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
You only need to run make (it defaults to using the Makefile in the current directory, and the default target is the first one, above the one named all), to recompile the TARGETS (here, test, but you can supply more by just adding them space-separated to the line).
You can also run make clean test to rebuild test from "scratch", i.e. removing all temporary files and all targets first.
You can override variables like CFLAGS by simply supplying them on the command line; for example, make CFLAGS="-Wall -Wextra -Os" clean all to recompile everything with different compilation flags.
I'm trying to make a static library (.a) but facing issues that I'm unable to understand. So in brief compiling with *.o succeeds but archiving them using ar and then using the .a file to compile gives me an undefined reference to 'symbol' error.
So here is a simple code.
test.c
#include <stdio.h>
#include <string.h>
int main()
{
hello_world();
return 0;
}
hello_world.c
#include<stdio.h>
void hello_world (void) {
printf("Hello World\n");
}
Compile.
gcc -c -o hello_world.o hello_world.c
ar crs libhello.a hello_world.o
gcc libhello.a -o test test.c
gives me the error
/tmp/ccsO7AJl.o: In function `main':
test.c:(.text+0xa): undefined reference to `hello_world'
Instead doing this works(Compiles and runs fine)
gcc -c -o hello_world.o hello_world.c
gcc hello_world.o -o test test.c
I have no idea what I have done wrong so any help is appreciated.
This is an almost duplicate of Why does the order of '-l' option in gcc matter? - but the behaviour can be replicated without the -l switch by specifying the archive name on command line.
The GNU linker as executed by GCC will, by default, link from left to right, and only use those .o files from the library archive that are needed to satisfy undefined references so far. Since your library precedes the main translation unit on the command line, hello_world is not required at the time the linker is processing it.
The solution is to mention the library after the translation units/object files that depend on it:
gcc -o test test.c libhello.a
I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main
I get an undefined reference error for the example below. I have seen lots of questions that relate to this issue but believe I gave a stripped, reproducible, conceptual example as opposed specific issues in other questions,
dynlib.h:
void printMe_dyn();
dynlib.c:
#include <stdio.h>
#include "dynlib.h"
void printMe_dyn() {
printf("I am execuded from a dynamic lib");
}
myapp.c:
#include <stdio.h>
#include "dynlib.h"
int main()
{
printMe_dyn();
return 0;
}
Build steps:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
gcc -Wall -L. -ldynlib myapp.c -o myapp
Error:
/tmp/ccwb6Fnv.o: In function `main':
myapp.c:(.text+0xa): undefined reference to `printMe_dyn'
collect2: error: ld returned 1 exit status
Proof that the symbol is in the library:
nm libdynlib.so | grep printMe_dyn
00000000000006e0 T printMe_dyn
Am I using the correct compiler flags for building the dynamic
library?
Is the proof I've presented really an unambiguous proof?
What other approach could be taken to diagnose the issue?
The order of appearance of libraries matter.
To quote the online gcc manual
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
You should be changing your compilation statement to
gcc -o myapp -Wall -L. myapp.c -ldynlib
to tell gcc to search for the symbols used in (compiled) myapp.c to be present in dynlib.
Just as additional notice. The same behavior one may obtain when the library has been built by gcc and linked to the c++ project. Like follows:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
g++ -o myapp -Wall -L. myapp.cpp -ldynlib
In such case the reason is name-mangling used by g++. To have it turned off one must wrap C-function prototypes by extern "C" within C-library. For example like follows:
dynlib.h:
#ifdef __cplusplus
extern "C"{
#endif
void printMe_dyn();
#ifdef __cplusplus
}
#endif
The order of libraries in linker command line matters. Fix:
gcc -o myapp -Wall -L. myapp.c -ldynlib
I'm pretty new to C and to programming so I hope you guys have a little patience.
However I try to describe my problem as precise as possible.
I'm using mingw32 on my Windows 7 computer and I just learned about 'make'.
I have written some source-code files and a Makefile. What I want is, that the Makefile
compiles my source-code int object code and then link it together to one executable
(I guess that's nothing wild for a pro).
So here is my code:
first.c:
#include<stdio.h>
#include"second.h"
int main()
{
float x = 12.0;
printf("Result is: %.2f\n",go_to_the_other(x));
return 0;
}
second.h
float go_to_the_other(float f);
second.c
float go_to_the_other(float f)
{
float calc = f + 10;
return calc;
}
And the Makefile is (and yes, I used only tabs):
second.o: second.c second.h
gcc -c second.c
first.o: first.c
gcc -c first.c
first: first.o second.o
gcc first.o second.o -o first
This is just an easy example, but it pretty much describes my problem.
I have all files in the same directory, and I use the command line:
mingw32-make first
But instead of compiling my files, I only get the message:
cc first.c -o first
process_begin: CreateProcess(NULL, cc first.c -o first, ...) failed
make (e=2): The system cannot find the file specified.
<builtin>: recipe for target 'first' failed
mingw32-make: ***[first] Error 2
I guess it's probably something really stupid, but I just can't figure out
what I'm doing wrong. I really appreciate any help on this.
Thank you so much in advance.
So I went and tried it and... it works for me with MinGW-4.7.1 on a Win7 machine.... I'm wondering if make it picking up an environment variable or some such.
Try verifiying the version of make and gcc are what you expect
mingw32-make -v
gcc -v
mingw32-gcc -v
Also Try this makefile and see what happens.
CC = mingw32-gcc
second.o: second.c second.h
$(CC) -c second.c
first.o: first.c
$(CC) -c first.c
first: first.o second.o
$(CC) first.o second.o -o first
Note convert spaces to tabs!
And compile via
mingw32-make SHELL=cmd.exe first
See what happens.