Symbols missing from Linux static library using NetBeans - c

I'm working on a C static library that's eventually going to be open-source, so I'm cross-compiling on Windows and Ubuntu to backstop for any portability issues.
The problem I'm having is that the symbols from one of the object files are omitted from the Linux build. When I build the library using VS2015 on Windows, all symbols are present.
I'm mostly used to developing for Windows, so I'm pretty spoiled to using an IDE for most build scenarios. On Ubuntu, I'm using NetBeans , and I'm not sure if the problem is with my understanding of gcc or if I don't have NetBeans set up correctly.
Details
Ubuntu 16.04LTS using gcc(Ubuntu) 5.4.0
NetBeans IDE 8.1 C/C++
The library consists of 3 source files and 2 header files:
queue.c --> queue implementation
memutil.c --> memory utilities
mylib.c --> main library implementation
queue.h --> included by queue.c and mylib.c
mylib.h --> header file for the static library
The mylib.h header contains the header information for the memutil.c source file, wrapped in a conditional that depends on the MEMCHECK symbol on the command line. Likewise for the code in the memutil.c source file. The MEMCHECK symbol is defined when building the library, but when I run nm on libmylib.a after the Linux build, no symbols are listed for the memutil.o object file. When i look at the mylib.lib file on Windows, all the symbols for memutil.obj are listed.
Now, if I add a stubbed out source file that just includes the mylib.h header, all of the symbols are present in the libmylib.a library. I'm guessing there's some sort of header file interaction malfunction going on, but I don't where to look to find out what it is or how to fix it. I have Google'd the snot out of this with as many different phrasings as I can think of, but no joy.
Here's the NetBeans build output, less all of the directory noise:
gcc -c -g -Wall -DMEMCHECK -MMD -MP -MF "build/queue.o.d" -o build/queue.o queue.c
gcc -c -g -Wall -DMEMCHECK -MMD -MP -MF "build/memutil.o.d" -o build/memutil.o memutil.c
gcc -c -g -Wall -DMEMCHECK -MMD -MP -MF "build/mylib.o.d" -o build/mylib.o mylib.c
ar -rv dist/Debug/GNU-Linux/libmylib.a build/queue.o build/memutil.o build/mylib.o
ar: creating dist/Debug/GNU-Linux/libmylib.a
a - build/queue.o
a - build/memutil.o
a - build/mylib.o
ranlib dist/Debug/GNU-Linux/libmylib.a
BUILD SUCCESSFUL (total time: 3s)
Stubbing in the header file inclusion can't be the fix for this, can it? It works, but it seems awfully crude. Besides, I can't really credit that it would be necessary with gcc and not necessary with VS2015.

Well, I found the solution, but I'm not marking this as the accepted answer because I'm not sure exactly why it's the solution.
I noticed the -Mxx flags on the compiler lines:
gcc -c -g -Wall -DMEMCHECK -MMD -MP -MF "build/...
So I went back to Google and found this site: Auto-Dependency Generation, which covers having Make handle the generation and tracking of build dependencies.
Then I starting combing through every single menu item in NetBeans until I found this one:
Tools->Options->C/C++->[on/off] Enable dependency checking in generated makefiles
I cleared that switch, and all of the missing symbols appeared in the library. However, the -Mxx flags were still present on the compiler lines in the build output. Now, the makefile generation for NetBeans uses about 5 separate makefile templates and 3 or 4 different XML configuration files to generate the makefile at build time, based on build configuration and target. I couldn't figure out if the auto-dependency flags were rendered inert by flipping that switch or not.
But, if I'm reading the information on the above-mentioned website correctly, those -Mxx flags are actually used by gcc in support of Make, so I'm not sure how they would have a different interpretation based on something that NetBeans did. Although, there are a LOT of substitutions in those makefile templates, and with me not being an Autoconfig/Make wizard, I may have simply missed it.
So, apparently, since none of the source files actually included the function prototypes for the memory utilities -- because they are contained in the library header file, which none of the library source files include (it's meant for inclusion by client code) -- the NetBeans dependency checker decided that those functions weren't needed in the library.

Related

GCC have include but not library

I'm writing my own kernel for fun, and in doing so I've needed to install glibc to use the standard C libraries. However, after installing the library to the desired directory, my kernel.c program includes the stdio.h header and attempts to use fopen, however I come across this error:
kernel.c:(.text+0x238): undefined reference tofopen'`
After looking around I noticed that I don't have any actual code to all of the header files, just the header files themselves. So I went and added the -L flag to GCC to add the lib folder that was created during the compilation of glibc and what I've found out is that the lib folder has nothing of what I need.
I poked around and found that the build directory I used when compiling glibc has the .o files I'm looking for (e.g it has iofopen.o for the fopen method).
So what's going on?
If needed, the commands I am using to compile my kernel are:
#!/bin/bash
nasm -felf32 boot.asm -o boot.o
/home/noah/opt/cross/bin/i686-elf-gcc -I/home/noah/Documents/NoahOS/include/ -L/home/noah/Documents/glibc/build -c *.c -std=gnu99 -ffreestanding -Wall -Wextra
/home/noah/opt/cross/bin/i686-elf-gcc -I/home/noah/Documents/NoahOS/include/ -L/home/noah/Documents/glibc/build -T linker.ld -o noahos.bin -ffreestanding -O2 -nostdlib *.o -lgcc
First line builds the boot file, which is assembly.
Second line runs gcc on all of the C language .c files and creates their object files.
Third line links all of the files together with linker.ld and outputs the final kernel to noahos.bin which is a runnable kernel using
qemu-system-i386 -kernel noahos.bin
If needed more information can be provided. Please ask.
You are correctly compiling your kernel using -nostdlib because the kernel can't use the standard library. Why not? Because it doesn't make sense: the standard library is the interface between user programs and the kernel, so that application developers don't need to know the system call specification for your kernel, all that is required is a port of the C library.
Oh, there's the answer. You need a port of the C library to use your own system calls. Starting with glibc might not be the easiest to port (it comes with the kitchen sink).

gcc and liboauth - linker can't find oauth.h

I'm trying to use liboauth with a C program, using gcc as my compiler, and no matter what I've tried I keep getting the error "ld: library not found for -loauth" and "clang: error: linker command failed with exit code 1".
I'm including the header via "#include <oauth.h>", and my most-recent call to gcc looked like this:
gcc -Wall -lcurl -loauth -I /usr/local/include -v -o api api.c
Now, oauth.h does exist in /usr/local/include, and there are a handful of liboauth files (including liboauth.a) located in /usr/local/bin, which I'm assuming were placed there when I ran the install. I will admit that I'm not very familiar with gcc and compiling non-trivial C programs, but I was able to get libcurl working on a fresh download in just a few minutes. I just can't figure out what's going on with liboauth.
Thanks in advance
If you are sure liboauth's located in /usr/local/bin use
gcc -Wall -L/usr/local/bin -I /usr/local/include -v -o api api.c -lcurl -loauth
It'd also be better to place libraries in the end of the command as there is some important stuff with them (they may depend on each other, etc).
By the way, it's pretty strange your libraries are in /usr/local/bin as libraries are almost always stored in some path like /usr/*/lib.

Custom compile of binutils/ld doesn't find symbols in archives

I'm currently trying to compile Clang/LLVM for a bare metal aarch64 target. Compiling Clang was straightforward - in fact I have compiled to target multiple architectures including arm and aarch64. For the backend I'm using binutils. Since binutils can only target one architecture I've built both aarch64 and arm versions of this. Again building seemed to be straightforward. I built binutils for aarch64 using:
mkdir build
cd build
../configure --target=aarch64-none-elf
make
from an unpacked source package of binutils 2.24.
The problem I'm having is that I can't get my custom build of ld to handle archive files properly. It seems to find and open archive files without a problem but fails to search it for undefined symbols when compiling the final binary. Here's some more concrete details via an example:
Create a simple main.s file by compiling:
int foo();
int main() { return foo(); }
with Clang and using --target=aarch64 -S, i.e. to emit an architecture specific assembly file.
Do the same to create foo.s by compiling:
int foo() { return 0; }
Assemble both .s files to .o files using custom gas build from binutils.
Create an archive libfoo.a by running custom ar and ranlib builds from binutils using ar cr foo.a foo.s and ranlib libfoo.a.
Try to link the two files together using ld -L. -lfoo -o main.elf main.o.
The output shows an undefined reference to foo.
bar.cpp:(.text+0x14): undefined reference to `foo()'
I can run readelf on foo.a and it seems perfectly well formed. In particular I can see the public symbol for foo. If I run ld with --verbose then I see
attempt to open ./libfoo.a succeeded
but no indication that it's found any symbols.
If I link directly with the object files, i.e. using ld -o main.elf foo.o main.o then I get a well formed elf file. Furthermore, if I extract foo.o back out of libfoo.a then I can also link succesfully with the extracted foo.o.
Does anyone have any ideas why this might be happening? I'm pretty sure my clang build is okay as the emitted assembly files effectively decouple the problem from clang. I'd guess also that the assembled .o files are fine. So this only leaves ar/ranlib or ld as the culprit.
To try to eliminate ar/ranlib as the culprits I rebuilt binutils for arm (same steps but using --target=arm-none-eabi). If I integrate the built ar/ranlib binaries into a known good arm-eabi-none GCC toolchain then they seem to work correctly. My suspicions thus point to ld at the moment. Note that I get the same problem with the main/foo example as above if I use my Clang build with the arm build of binutils.
I also tried integrating the arm version of ld into the existing known good GCC toolchain, but got:
this linker was not configured to use sysroots
Need to figure that out. That's still a bit cryptic for me right now. It prevents me from sanity checking the arm ld build.
It might well be that I'm doing something obviously wrong, but right now I don't see it.
Notes:
I had to hack the make script for binutils to add a couple of -Wno-xxx flags. I need to do this the "correct" way, but I don't think this hack should affect the output.
I'm building/hosting all tools on OSX 10.9.4 64-bit.
UPDATE:
The error about sysroots is simple. The pre-existing toolchain was configured with flags:
--with-prefix $SOME_INSTALL_DIR
--with-sysroot $SOME_INSTALL_DIR/arm-none-eabi
If I rebuild with these then I can slot in my ld version without a problem and it works. I got excited thinking that this might have been my mistake. Previously I wasn't running make install as I didn't really care about installing at this stage. I thought perhaps my new build of ld was referencing OSX system libs/exes somehow (although I'm not sure exactly what it could reference, other than perhaps ar, i.e. if it runs ar to handle archives). However I still have the same problem with both the arm and arrach64 versions of binutils even when configured like this.
Looks like I was dramatically overthinking the problem and also missing something I'd never quite realised about ld. The issue was with the line:
ld -L. -lfoo -o main.elf main.o
I hadn't realise that ld is sensitive to object file/library ordering. The undefined reference to foo() was in main.o. I specified the library libfoo.a as input before main.o is parsed. This means that the linker doesn't bother searching libfoo.a for the symbol as it's already processed this library. main.o must be specified before, e.g.
ld -L. main.o -lfoo -o main.elf
Even wrapping -lfoo with --start-group ... --end-group doesn't fix this.
I'm still feeling somewhat surprised by this. And I've yet to convince myself it's a good feature of ld. Seems like the only use case I can think of right now is to sneakily allow duplicate symbols.
Time for a cup of tea!

C - Compile with dependencies included

I have some code which I want to run on a machine which I do not have root access to.
That machine does not have some of the libraries needed to run this code.
Is there any way to include all dependencies when I compile? I realize the resultant file may be quite large.
What you're looking for is static compiling. Performing static compilation includes all of the libraries into the executable itself, so you don't have to worry as much about dependency chains on a specific system, distribution, etc.
You can do this with:
gcc -Wl,-Bstatic -llib1 -llib2 file.c
The -Wl passes the flags following to the linker, -Bstatic tells it to link static if possible, and then lib1, lib2, are the libs you intend to link.
Alternatively, try:
gcc -static file.c
The compilation will still need to match the architecture of the non-privileged system. And you need to have the static libraries installed on the compiling system (lib.a)
If compiled properly, it should show "not a dynamic executable" when you run:
ldd a.out

Correct syntax checkin with external makefile

I've made a Makefile project (New -> C Project -> Makefile project). And it's correctly compiles.
But syntax checker is not working properly because of Eclipse doesn't import some important options from makefiles. -I (header folders) for example.
How to solve this problem?
Eclipse uses build output generated by your makefiles to parse compilation flags, inclusion paths, predefined macros, etc. It expects that your build system echoes each command it executes.
That is, it will not work, if the output of make looks like this:
[CC] foo.o
[CC] bar.o
[LD] baz
Make sure, that it prints raw commands, like:
gcc -Ipath/to/include -DFOO=1 -O2 ... -o foo.o -c foo.c
gcc -Ipath/to/include ... -o bar.o -c bar.c
ld foo.o bar.o -o baz
Some build tools provide an option to enable a verbose mode (like make V=1). However, handwritten makefiles are usually OK, because Make echoes executed commands by default.
In this case Eclipse will be able to recognize build options (like path/to/include or FOO=1) and use them to setup C/C++ indexer.
Related project settings
Configuring the project:
In C/C++ Build -> Discovery Options check these entries:
Automate discovery of paths and symbols
Discovery profile: GCC per file scanner info profile
Enable build output scanner info discovery
After that you need to perform a fresh build from inside Eclipse (Clean Project, then Build Project), so that it will see a complete build log.
This feature is rather fragile, and gets broken sometimes... Usually it helps to flush the index using Project -> Index -> Rebuild.

Resources