"undefined reference" error after adding function to a C project - c

I've added a new function wiringPiVersion() to wiringPi, but after I build and install the shared library, when I attempt to compile a small C program around it, I get:
wpi_ver.c:(.text+0xc): undefined reference to `wiringPiVersion'
However, when I include it in an XS based Perl module, all works well. I don't know enough about C to figure out what's going wrong here, and I've been searching for the better part of two hours trying different things to no avail.
Here's my small C program to test the new function:
#include <stdio.h>
#include <wiringPi.h>
int main (){
char * ver = wiringPiVersion();
printf("wiringPi version: %s\n", ver);
return 0;
}
Compilation that throws the error:
gcc -o ver wpi_ver.c -lwiringPi
The addition to wiringPi's header file:
extern char * wiringPiVersion(void);
The wiringPi's .c file addition:
#define WPI_VERSION "2.36"
char * wiringPiVersion(void){
return WPI_VERSION;
}
In my Perl module's XS file, I have:
char *
wiringPiVersion()
...and my Perl module's Makefile.PL
LIBS => ['-lwiringPi'],
...and after re-installing the Perl module, I can access the function without any issues in a test script.
I'm hoping this is something simple I'm overlooking which someone may be able to point out. My question is, how do I rectify this?

So it turned out that there were two .so files generated when I rebuilt wiringPi... one in the wiringPi's build directory way under my home directory, and the other in /usr/local/lib.
After a tip in comments, I added the library path explicitly:
gcc -o ver wpi_ver.c -L/usr/local/lib -lwiringPi
...and it all fell together and works as expected:
$ ./ver
wiringPi version: 2.36
Note: I have sent Gordon the patch in hopes it gets included in the next wiringPi cut.
Update: I received an email back from Gordon and he stated that currently, only the gpio application has the ability to report the version, so he advised that he's going to add something similar to my patch in a future release.

Although already solved, I added this answer to show what gave me the hint.
Error message "undefined reference" points to a linker error (cf. answer on SO), so its about checking if the correct library is drawn.

Related

Problems while compiling XDR on macOS (RPC types.h issue)

I am trying to compile some source codes about UNIX scokets programs, on Linux I have no problems but on macOS I get stuck in front of types definition problems. I don't know how many details I can put here, but I'll try.
The source codes to be compiled are:
errlib.c
errlib.h
server_test.c
sockwrap.c
sockwrap.h
where the main is located in server_test.c.
To compile I use:
gcc -Wall -DTRACE -o server_test server_test.c errlib.c sockwrap.c
There are no problems running this on Linux, but on macOS I get more than 20 error and all of these are about a (perhaphs) missing definition of bool_t. I suppose something not working in /usr/include/rpc/* files located in macOS internal libraries.
So I looked for if <sys/types.h> is included in /usr/include/rpc/xdr.h and it seems to be not missing.
Some of the first lines of the gcc output are:
In file included from server_test.c:16:
/usr/include/rpc/xdr.h:126:3: error: type name requires a specifier or qualifier
                bool_t  (*x_getlong)(struct __rpc_xdr *, int *);
                ^
/usr/include/rpc/xdr.h:126:10: error: function cannot return function type 'int (struct __rpc_xdr *, int *)'
                bool_t  (*x_getlong)(struct __rpc_xdr *, int *);
                        ^
/usr/include/rpc/xdr.h:128:3: error: type name requires a specifier or qualifier
                bool_t  (*x_putlong)(struct __rpc_xdr *, const int *);
                ^
/usr/include/rpc/xdr.h:128:10: error: function cannot return function type 'int (struct __rpc_xdr *, const int *)'
                bool_t  (*x_putlong)(struct __rpc_xdr *, const int *);
                        ^
/usr/include/rpc/xdr.h:128:3: error: duplicate member 'bool_t'
                bool_t  (*x_putlong)(struct __rpc_xdr *, const int *);
                ^
/usr/include/rpc/xdr.h:126:3: note: previous declaration is here
                bool_t  (*x_getlong)(struct __rpc_xdr *, int *);
                ^
/usr/include/rpc/xdr.h:136:3: error: type name requires a specifier or qualifier
                bool_t  (*x_getbytes)(struct __rpc_xdr *, char *, unsigned int);
...
and many others lines that are very similar.
For those who want to deepen, the sources are available here.
What could be the problem?
The bad answer
Issue solved by simply including <rpc/types.h> in the server_test.c source as follows:
#include <rpc/types.h>
The better one
This is a solution above is valid only for this server_test.c implementation.
If you want fix this issue "globally", you can follow follown steps:
disable SIP (how to? here)
get your macOS's xdr.h (from here /usr/include/rpc/xdr.h)
copy it elsewhere two times: one copy is for backup and modify the other one simply adding the required include (#include <rpc/types.h> and see the picture below)
overwrite your modified xdr.h onto the original one in /usr/include/rpc/
re-enable SIP
Here is how I did it:

C: How to include the squash compression library?

I'm fairly new to programming with c and i am having a hard time including the squash library into my program.
I cloned the repository and ran ./configure and make sudo make install.
That installed the files:
/usr/local/lib/pkgconfig/squash-0.8.pc
/usr/local/lib/libsquash0.8.so.0.8
/usr/local/lib/libsquash0.8.so.0.8.0
/usr/local/lib/libsquash0.8.so
/usr/local/lib/cmake/Squash-0.8.0/SquashConfig.cmake
/usr/local/bin/squash
And some more files in this directories:
/usr/local/include/squash-0.8/
/usr/local/lib/squash/0.8/plugins/
In the squash examples the library is included by #include <squash/squash.h> but when i am trying to compile it i get fatal error: squash/squash.h: No such file or directory
Also #include <squash-0.8/squash.h> doesnt work because then i get fatal error: hedley/hedley.h: No such file or directory That file is located at
/usr/local/include/squash-0.8/squash/hedley/hedley.h
I guess the solution is pretty simple for an experienced c programmer but i am failing here..
Do i need to set some sort of environment variable to let the compiler find the library?
And how do i link the library to the compiler anyway?
I found something like:
-rdynamic ../squash/libsquash0.8.so.0.8 but could not test it yet because of the error above.
Try to change
#include <squash/squash.h>
to
#include "squash/hedley/hedley.h"
or
#include "<squash-0.8/squash/hedley/hedley.h>"
easier and faster solution would be adding the path to your includes during compilation:
-I/usr/local/include/squash-0.8/squash/

Using Go code in an existing C project

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.
The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)
Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.
However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)
I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?
The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke
Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"
To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
func main() {}
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):
...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...
So that's enough to call the exported function. We can write a simple C program that calls it like so:
#include "foo.h"
int main(int argc, char **argv) {
PrintInt(42);
return 0;
}
We can compile it with a command like:
gcc -pthread foo.c foo.a -o foo
The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.
The code above work just fine, but gcc will complain about functions and headers.
The includes should be:
#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"
If you forget the #define _GNU_SOURCE, the gcc will complain:
warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]
If you forget the #include "mygopkg.h", the gcc will complain:
warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]
The last but not less important. The build command line I recommend for production code is:
go build -ldflags "-s -w" -buildmode c-archive -o mygopkg.a
It'll save you 53% size of final mygopkg.a.

YouCompleteMe suggests only "local" used code

I'm trying to use YCM for the first time so in order to make it work I decided to give a chance for the YCM-Generator, which generates the .ycm_extra_conf.py file automatically based on the makefile.
So far my program is just a simple hello world.
#include <stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
I'm using the CMakeLists.txt trick to generate the makefile.
file(GLOB sources *.h *.c)
add_executable(Foo ${sources})
then after executing the YCM-Generator script, I get this output
Running cmake in '/tmp/tmp_YknVy'... $ cmake
/home/pedro/Desktop/Projetos/teste
Running make... $ make -i -j4
Cleaning up...
Build completed in 1.5 sec
Collected 2 relevant entries for C compilation (0 discarded).
Collected 0 relevant entries for C++ compilation (0 discarded).
Created YCM config file with 0 C flags
YCM plugin does find the .ycm_extra_conf.py file, but the auto-completion doesn't work right, for example, if I type "floa", it doesn't suggests "float", but It only suggests things that I used before like "int" or "printf".
Am I missing something or this is working as intended?
So I fixed it.
For c it does require a .ycm_extra_conf.py , while a friend of mine could make it work without one in c++.
The auto complete only suggest automatically functions that were previously used, if you don't remember a function name you have to press <Ctrl-Space>
YCM-Generator didn't do the job, so I modified the example file myself following the comments.
If you are used to Visual Assist, the auto complete works but it's really weak if compared to VA, which is a shame... I really hope someone port that plugin to Linux.

Call method from source file in another directory

I have a newbie question about the C programming language. I have looked around to find the answer in similar questions but I failed to figure it out.
Assume a simple project consisting of two dirs: src and test. The source and header files are defined by src/main.c, test/foo.h and test/foo.c.
src/main.c:
#include "../test/foo.h"
int main (void) {
int a = VAR; /* works, recognizes declared macro */
some_function(a); /* doesn't work, "undefined reference" */
}
test/foo.h:
#ifndef FOO_H
#define FOO_H
void some_function(int a);
#define VAR 2;
#endif
test/foo.c (redundant but to be complete):
#include "foo.h"
#include <stdlib.h>
void some_function(int a) {
printf("%d", ++a);
}
I created the project in Eclipse and I also compile with it, I figured it wasn't a linking error since the macro gets recognized but the method is not callable.
The reason why I'm using different directories is because I have a lot of files and would like my test code to be separate from my main source code. Note that src and test have the same parent directory.
Any ideas what's going on here? Am I missing something very obvious?
Any help would be much appreciated, thanks in advance!
edit: I'm working on a (Debian) Linux machine and Eclipse uses the gcc compiler.
edit2: Thanks to H2CO3's answer I learned it is indeed a linking error. Since compiling and linking manually every time is quite an overhead, I was wondering if anyone knows how to teach Eclipse to link executables from different directories?
--------------------- SOLUTION ---------------------
edit3: Lol the solution was very easy after all, all I had to do was create a "new source folder" rather than a "new folder". I feel stupid but thanks to you all for replying, H2CO3 in particular!
I figured it wasn't a linking error since the macro gets recognized but the method is not callable.
Non sequitur. Macros are expanded in the preprocessing phase. (And as such, they have nothing to do with linkage at all.) You do have a linker error.
What you have to do is compile both files then link them together, so something like this should work:
gcc -Wall -o dir_one/foo.o dir_one/foo.c
gcc -Wall -o dir_two/bar.o dir_two/bar.c
gcc -o my_program dir_one/foo.o dir_two/bar.o
Also, read this SO question/answer and/or this article to understand how the steps of the compilation process work together. (These are almost the same for C and C++, it's only the name mangling that usually differs.)

Resources