gcc linking two files not working in macOS - c

For my compiler course, I'm following the Incremental Approach to Compiler Construction by Abdulaziz Ghuloum with the accompanying tutorial. At some point, we have the following two .c files:
runtime.c
#include <stdio.h>
int main(int argc, char** argv) {
printf("%d\n", entry_point());
return 0;
}
ctest.c
int entry_point() {
return 7;
}
The author then runs the following commands:
$ gcc -Wall ctest.c runtime.c -o test
[bunch of warnings]
$ ./test
7
$
But when I run $ gcc -Wall ctest.c runtime.c -o test I get the following error:
runtime.c:9:20: error: implicit declaration of function 'entry_point' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
printf("%d\n", entry_point());
I want to be able to compile and link my two .c files the same way the author did using gcc, but it keeps throwing me that error. I've been doing some research but the same command ($ gcc file1.c file2.c -o combined) keeps coming up. Help would be appreciated.
I'm running this on MacOS Monterey 12.6 and doing gcc --version displays:
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Thanks in advance

On macOS, the default compiler is clang, not gcc. The later is just a symlink to clang so that's something to keep in mind.
Clang sees the call to entry_point() in runtime.c and doesn't know it yet. Traditional C for such an undefined function is to assume it returns int and does not accept arguments. But Clang goes the safe route by default and instead of just warning about it, treats this as an error since most of the time this assumption is just false and may cause runtime issues.
You have multiple options:
Add a header file that defines int entry_point(void); and #include it in your runtime.c.
Add the line int entry_point(void); near the top of your runtime.c.
Pass -Wno-error=implicit-function-declaration to the compiler.

Related

GCC link against .so file without souce code

I am trying to compile compile a simple "hello world" program for an Axis A210 (cris architecture). I managed to get download GCC from the vendor, but it came with glibc, and the camera is running uClibc-0.9.27. I pulled the file /lib/libuClibc-0.9.27.so from the device.
I managed to compile this program that segfaults:
#include <unistd.h>
int main(int argc, char** argv)
{
*((unsigned int*)0) = 0xDEAD;
}
and this program that just hangs:
#include <unistd.h>
int main(int argc, char** argv)
{
int a = 0;
}
with cris-gcc -g -static -nostdlib -o compiled main.c.
Now I'd like to use the functions in libuClibc, but I can't seem to get the linking to work: I've tried
cris-gcc -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.
but that just gives:
./libuClibc-0.9.27.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
Is there a way to link to this .so file or to otherwise get some standard functions like exit working?
regarding:
cris-gcc -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.
The linker works with libraries in the order they are encountered. So they must be listed in the order needed.
The linker needs to know where the library is located before knowing which library to examine. Suggest:
cris-gcc -g -static -nostdlib -o compiled main.c -L. -luClibc-0.9.27
However, a *.so library is NOT a static library. It is a dynamic library, so the option: -static should be removed However, that requires that the dynamic library be available at 'run time' if the related *.a (a static library) is available then it should be used in the compile/link statement.
Note: the function: exit() has its' prototype exposed via the stdlib.h header file, not the unistd.h header file.
regarding:
#include <unistd.h>
int main(int argc, char** argv)
{
*((unsigned int*)0) = 0xDEAD;
}
the parameters: argc and argv are not used, so the compiler will output two warning statements about 'unused parameters'. Suggest using the function signature: int main( void )
this code is trying to write to address 0. However, the application does not 'own' address 0, (an usually, such an address will be 'marked' as 'readonly' so the application will exit with a 'seg fault event')
it is poor programming practice to include header files those contents are not used. Suggest removing the statement: #include <unistd.h>
this statement: int a = 0; will result in the compiler outputting a warning message about a variable that is 'set' but never 'used'
regarding:
cris-gcc -g -static -nostdlib -o compiled main.c -L. -luClibc-0.9.27
When compiling, should always enable the warnings, then fix those warnings. Suggest:
cris-gcc -Wall -Wextra -Wconversion -pedantic -std=c99 -g -static -nostdlib -o compiled main.c -luClibc-0.9.27 -L.
Apart of all the problems noticed by #user3629249 in his answer (all of them are to be followed), the message:
./libuClibc-0.9.27.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
means that the libuClibc-0.9.27.so binary has been stripped its symbols or you have not privileges to read the file, and so, the symbol table. The linker is unable to use that binary and it can only be loaded into memory. Anyway, you need a nonstripped shared object, and as suggested by #user3629249, don't use -static (by the reason stated in his answer), put the parameters in order (library dir before the library to be linked, also stated by him). Even you can link the shared by specifying it as:
cris-gcc -nostdlib -o compiled main.c libluClibc-0.9.27.so
and another thing: You need not only the standard C library to link an executable... you normally use a crt0.o at the beginning of your program with the C runtime and the start code for your program. You have not included that, and probably the compiler is getting it from another place.
One question: If you got the compiler, why do you intend to supply your own version of the standard library? isn't provided by the compiler? If you change the libc, then you must change also the crt0.o file. It defaults to some compiler provided, and you haven't received the message no definition for start.
Try to compile with just a main function, as you did, but don't specify shared libraries or directories... just the main code:
cris-gcc -o compiled main.c
and see what happens.... this will be very illustrative of what you lack in your system.

GCC Linux C - Compile object header not found

I've been working on a module in C (under Linux) that requires another module (headers are in other directories).
My problem is that when I compile the code with my Makefile, the gcc compiler tells me that some headers aren't found.
gcc -c render.c
So I include the directories to find the header but here, gcc tries to find the "main" function which does not exist: it is a module...
gcc /opt/vc/include -c render.c
So I would like to know how is it possible to compile a module (output in module.o) that requires other modules?
Here are my files:
render.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "render.h"
int width,height;
int loop,counter;
int initRender(void(*setup)(void),void(*draw)(void),void(*end)(void))
{
init(&width, &height);
loop = -1;
counter = 0;
setup();
while(loop==-1)
{
Start(width, height);
draw();
End();
counter++;
}
end();
finish();
exit(0);
return 0;
}
render.h:
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
#ifndef RENDER_H_
#define RENDER_H_
extern int width,height;
extern int loop,counter;
int initRender(void(*setup)(void),void(*draw)(void),void(*end)(void));
#endif
Makefile:
INCLUDEFLAGS=-I/opt/vc/include -I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include/interface/vcos/pthreads -IopenVG
LIBFLAGS=-L/opt/vc/lib -lGLESv2 -lEGL -lbcm_host -lpthread -ljpeg -LopenVG
NEEDED= openVG/libshapes.o openVG/oglinit.o
all: render
render.o: render.c
gcc -Wall -g $(INCLUDEFLAGS) -c render.c
You probably want
gcc -Wall -g -I/opt/vc/include -c render.c
this will produce a render.o object file.
Please take time to read the documentation about invoking GCC. In particular, check what every option -Wall, -g, -I and -c means. IMHO the first two are very important.
Later, you probably want to link all your object files into an executable, with some external libraries. Perhaps you want something like
gcc -g -Wall -L/opt/vc/lib render.o main.o -lvc -o myprogram
(you really want the -Wall and -g options; IMHO you need to be an expert to dare avoiding them; once you have debugged your program and want to benchmark it, add -O2 for optimizations)
But surely, you want other options.
Notice that order of arguments to gcc matters a lot
Of course, you should learn about GNU make and you need to use it. See this and that examples. You might use make --trace (with recent make) or remake to debug your Makefile (which is not good). You should also run once make -p to understand more the builtin rules of make.
Perhaps you want a library, then read the Program Library HowTo.

erl_interface linker error

I need to use erl_interface in my C-program. There is Erlang R15B01 on Debian Wheezy.
I just do the following (for example).
// main.c
#include <ei.h>
#include <erl_interface.h>
int main() {
erl_init(NULL,0);
return 0;
}
Then i say:
cc -I/usr/lib/erlang/lib/erl_interface-3.7.7/include -L/usr/lib/erlang/lib/erl_interface-3.7.7/ -lei -lerl_interface -o prog main.c
Directory specified as -L contains libei.a and liberl_interface.a but linker abusing that reference to erl_init is undefined: undefined reference to erl_init
What may be wrong? Sorry for really stupid question.
Newest versions of the GNU toolchain require that the object files and libraries be specified in the same order their symbols depend on each other. So you should generally put the library flags to the end of the invocation, like this:
gcc -o prog main.c -L<libdir> -I<includedir> -lerl_interface -lei

gcov: cannot open graph file

I am trying to use gcov. I have this simple file a.c:
int main() {
return 0;
}
So I do
gcc -fprofile-arcs -ftest-coverage a.c -o a
./a
gcov a.c
and I get
a.gcno:cannot open graph file
Am I doing something wrong? I'm under Mac OS X Lion.
By default on Lion, "gcc" is not gcc. It's LLVM. And it doesn't support generating test coverage data.
If you run gcc-4.2 -fprofile-arcs -ftest-coverage a.c -o a instead that will use a real gcc, and it'll probably work.
Are you sure you are running the command from the same directory as the source file? You must be in the same directory, unless you specify the -o flag. Try:
gcov -o a.c
Try using clang instead of gcc. I had the same problem, and using clang fixed it for me.
Often this happens when the version of gcov you're running doesn't match the version of GCC used to compile the application. On some systems, package managers have odd practices in how they link GCC and gcov. For example on many systems gfortran is the same as gfortran-5 but gcov might be something old and crusty.
I used the following on Mac 10.8.4:
Installed via xcode the command line tools:
wrote this example code from the gcc website:
#include <stdio.h>
main()
{
int i, total; total = 0;
for (i = 0; i < 10; i++)
total += i;
if (total != 45)
printf ("Failure\n");
else
printf ("Success\n");
}
Compiling using the real GCC gcc-mp-4.7 -fprofile-arcs -ftest-coverage tmp.c
And using GCC's gcov: gcov-mp-4.7 -b tmp.c will give you this output:
File 'tmp.c'
Lines executed:87.50% of 8
Branches executed:100.00% of 4
Taken at least once:75.00% of 4
Calls executed:50.00% of 2
Creating 'tmp.c.gcov'

How do I add a directory to C header include path?

I am having trouble installing a dependency for a program that itself depends on pcre.h. I have this installed to /opt/local/include, but the C compiler does not see it and thus gives me:
error: pcre.h: No such file or directory
I have confirmed this by writing a hello world program that tries to include it:
#include <pcre.h>
#include <stdio.h>
int main(void)
{
printf("hello, world\n");
return 0;
}
This also gives the error unless I specify the path as </opt/local/include/pcre.h>.
I would like the C compiler to find this by default but I do not know where this is configured. Tab completion hasn't revealed any HEADER_PATH environment variables and I cannot find anything like it that isn't specific to XCode. I am, however, using Mac OSX Snow Leopard on the off chance that makes a difference.
Use -I /opt/local/include on the command line or C_INCLUDE_PATH=/opt/local/include in the environment.
Use the pcre-config utility to get the right flags:
$ pcre-config --libs --cflags
-L/opt/local/lib -lpcre
-I/opt/local/include
If you're compiling via the command line,
$ gcc -Wall -g `pcre-config --libs --cflags` main.c

Resources