RaspberryPi: undefined reference to `i2c_smbus_read*' functions in C userspace - c

I'm trying to compile a userspace C sourcefile which uses i2c_smbus_read_* and i2c_smbus_write_* functions in a Raspberry Pi 3B+ with kernel 5.10.63-v7+. It should be possible, according to this Linux kernel document. I already installed libi2c-dev.
If I use:
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
and I run gcc myfile.c -o myfile, I get:
/usr/bin/ld: /tmp/ccIWkqsK.o: in function `i2c_read':
myfile.c:(.text+0x84): undefined reference to `i2c_smbus_read_byte_data'
/usr/bin/ld: /tmp/ccIWkqsK.o: in function `i2c_write':
myfile.c:(.text+0x160): undefined reference to `i2c_smbus_write_block_data'
collect2: error: ld returned 1 exit status
Which could it be the problem?
Note that these functions are present in my /usr/include/i2c/smbus.h:
...
extern __s32 i2c_smbus_read_byte_data(int file, __u8 command);
extern __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
extern __s32 i2c_smbus_read_word_data(int file, __u8 command);
...

I agree you don't need extern "C"in a C program. Check your headers and see if your header defines the function as inline or not. If it only declares it, you need to find out which library is the function defined in and link the library in your program.
Edit: I see you already updated the question. In this case you need to link the i2c library similar to what they do here. Just add a parameter to your gcc command: -li2c.

Related

Error: L6218E: Undefined symbol three()

[Edit: The question is flawed, the file I described as "main.c" was actually "main.cpp" and that it why I was having an issue, calling a C function from a C++ file. The question is thus incorrect and doesn't have an answer, but if you have this undefined symbol issue, also think about checking you're not mixing C & C++.]
I'm using uVision 5 to develop a firmware, however I can't get the linker to find one of my functions.
main.c :
#include "Test.h"
int main()
{
return three();
}
Test.h :
#ifndef TEST_H
#define TEST_H
int three();
#endif
Test.c
#include "Test.h"
int three()
{
return 3;
}
All those files are at the root of my project, I know they get compiled as if I introduce a syntax error in them, compiler reports an error.
Also looking at the map file produced, I see that three() was removed:
Removing test.o(i.three), (4 bytes).
For testing purposes, I had --no_remove to linker command line, map file now contains:
0x0002ba76 0x00000004 Code RO 1 i.three test.o
So obviously, the linker is well aware of my function, and will or won't remove it depending on flags.
Regardless, it reports:
.\build\uvision5\test.axf: Error: L6218E: Undefined symbol three() (referred from main.o).
Not enough information to list image symbols.
Flawed question, it was actually a case of mixing C/C++, in which case you'll get a symbol missing if you call a C function from C++ without declaring it extern C.

Using cygwin to compile a c application using ftd2xx.lib by FTDI

I'm trying to compile a sample 64-bit c progam using the ftd2xx lib by FTDI using gcc within cygwin without any success. I always end up in linker errors.
My project contains these file:
main.c My Sample Application
ftd2xx.h The header of the library
ftd2xx.lib Importlibrary
ftd2xx64.dll dynamic library 64 bit
wintypes.h Wrapper used by ftd2xx.h to include windows.h
This is my main function:
#include <stdio.h>
#include <windows.h> // for windows specific keywords in ftd2xx.h
#include "ftd2xx.h" // Header file for ftd2xx.lib
int main()
{
FT_HANDLE ft_handle; // handle to the USB ic
FT_STATUS ft_status; // for status report(error,io status etc)
ft_status = FT_Open(0,&ft_handle); //open a connection
if(ft_status == FT_OK) //error checking
{
printf("\n\n\tConnection with FT 232 successfull\n");
}
else
{
printf("\n\n\tConnection Failed !");
printf("\n\tCheck device connection");
}
FT_Close(ft_handle); //Close the connection
return 0;
}
This is my linker cmd
Building target: testSimple.exe
Invoking: Cygwin C Linker
gcc -L/cygdrive/e/jschubert/workspaces/testSimple/ -o "testSimple.exe" ./main.o -lftd2xx
And here is my output
/cygdrive/e/jschubert/workspaces/testSimple//ftd2xx.lib(FTD2XX.dll.b):(.text+0x2): relocation truncated to fit: R_X86_64_32 against symbol `__imp_FT_Open' defined in .idata$5 section in /cygdrive/e/jschubert/workspaces/testSimple//ftd2xx.lib(FTD2XX.dll.b)
/cygdrive/e/jschubert/workspaces/testSimple//ftd2xx.lib(FTD2XX.dll.b):(.text+0x2): relocation truncated to fit: R_X86_64_32 against symbol `__imp_FT_Close' defined in .idata$5 section in /cygdrive/e/jschubert/workspaces/testSimple//ftd2xx.lib(FTD2XX.dll.b)
After reading the article How does the Import Library work? Details? and http://www.mikrocontroller.net/topic/26484 I'm pretty shure that there is a problem with the generated export lib functions. But how do I correct them?
On Cygwin -mcmodel=medium is already default. Adding -Wl,--image-base -Wl,0x10000000 to GCC linker fixed the error.

Detect -nostdlib or just detect whether stdlib is available or not

I have a homework assignment that requires us to open, read and write to file using system calls rather than standard libraries. To debug it, I want to use std libraries when test-compiling the project. I did this:
#ifdef HOME
//Home debug prinf function
#include <stdio.h>
#else
//Dummy prinf function
int printf(const char* ff, ...) {
return 0;
}
#endif
And I compile it like this: gcc -DHOME -m32 -static -O2 -o main.exe main.c
Problem is that I with -nostdlib argument, the standard entry point is void _start but without the argument, the entry point is int main(const char** args). You'd probably do this:
//Normal entry point
int main(const char** args) {
_start();
}
//-nostdlib entry point
void _start() {
//actual code
}
In that case, this is what you get when you compile without -nostdlib:
/tmp/ccZmQ4cB.o: In function `_start':
main.c:(.text+0x20): multiple definition of `_start'
/usr/lib/gcc/i486-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o:(.text+0x0): first defined here
Therefore I need to detect whether stdlib is included and do not define _start in that case.
The low-level entry point is always _start for your system. With -nostdlib, its definition is omitted from linking so you have to provide one. Without -nostdlib, you must not attempt to define it; even if this didn't get a link error from duplicate definition, it would horribly break the startup of the standard library runtime.
Instead, try doing it the other way around:
int main() {
/* your code here */
}
#ifdef NOSTDLIB_BUILD /* you need to define this with -D */
void _start() {
main();
}
#endif
You could optionally add fake arguments to main. It's impossible to get the real ones from a _start written in C though. You'd need to write _start in asm for that.
Note that -nostdlib is a linker option, not compile-time, so there's no way to automatically determine at compile-time that that -nostdlib is going to be used. Instead just make your own macro and pass it on the command line as -DNOSTDLIB_BUILD or similar.

How to change the name of executable entry point from main to something else?

I'm trying to compile third party source code using gcc 4.8 on Ubuntu Linux (12.04 x64) with a lot of utilities and test applications where executable entry point is not called main. Don't ask me why - I don't know the answer.
Linker of course complains:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Is it possible to force linker to use another method as the entry point? I tried to use these linker options with gcc but neither of them worked:
-Wl,-eWhatever or -Wl,--entry=Whatever or -Wl,-e,Whatever. All ended with the same error.
As by C Standard, the hosted environment (that I guess is your case as/if you want to use standard library headers*) forces you to keep with main function. From C11 §5.1.2.2.1/p1 (emphasis mine):
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as
argc and argv, though any names may be used, as they are local to the
function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other
implementation-defined manner.
There are two options that I can think of to bypass main function requirement in your situation:
Create separate object file (that is, by gcc -c) with main symbol, that just (declares and) calls (i.e. wraps) your custom entry point (possibly passing through argc and argv invocation arguments). This would make linker happy and is as simple as adding single makefile rule.
Compile your program as gcc -DWhatever=main. This essentially replaces every instance of Whatever preprocessing token by main, so linker thinks of Whatever as "proper" main function.
* some headers must be available in freestanding environment too, such as <stddef.h> and <float.h>, see §4/p6 for full list of them.
Here is some basic ilustration of both options. Each assumes, that foo.c is as following:
foo.c
#include <stdio.h>
void foo(void)
{
printf("foo\n");
}
First method:
main.c
/* declare an entry point */
void foo(void);
/* define main as wrapper function */
int main(void)
{
foo();
return 0;
}
Compile & run:
$ gcc -c main.c
$ gcc foo.c main.o
$ ./a.out
foo
Second method:
$ gcc -Dfoo=main foo.c
$ ./a.out
foo
Some things may require more tweaking, but I hope you catch the idea.

undefined reference to function declared in *.h file

I am a unskilled programmer and new to linux, I run into a problem when complining. I have two files 'ex_addinst.c' and 'lindo.h' in the same folder, I input command :
g++ -c ex_addinst.c
then, a object file ex_addinst.o is genetated with a warning:
ex_addinst.c: In function ‘int main()’:
ex_addinst.c:80: warning: deprecated conversion from string constant to ‘char*’
then I leak them with
g++ -Wall -o ex_addinst ex_addinst.o
and get the following info:
ex_addinst.o: In function `main':
ex_addinst.c:(.text+0x2b): undefined reference to `LSloadLicenseString'
ex_addinst.c:(.text+0x75): undefined reference to `LSgetVersionInfo'
ex_addinst.c:(.text+0xae): undefined reference to `LScreateEnv'
ex_addinst.c:(.text+0x10a): undefined reference to `LSgetErrorMessage'
...
...
ex_addinst.c:(.text+0x1163): undefined reference to `LSdeleteEnv'
collect2: ld returned 1 exit status
I guess that the header file 'lindo.h' is not complied into the .o file, but I have no idea what to do now. I have tried gcc, but get the same error. the version of my g++ and gcc is 4.4.5. I am using Ubuntu 10.10.
All the functions and structures have been declared in 'lindo.h'.
part of ex_addinst.c is as follows:
#include <stdio.h>
#include <stdlib.h>
/* LINDO API header file */
#include "lindo.h"
enter code here
int CALLTYPE LSwriteMPIFile(pLSmodel pModel,
char *pszFname);
/* Define a macro to declare variables for
error checking */
#define APIERRORSETUP \
int nErrorCode; \
char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
/* Define a macro to do our error checking */
#define APIERRORCHECK \
if (nErrorCode) \
{ \
if ( pEnv) \
{ \
LSgetErrorMessage( pEnv, nErrorCode, \
cErrorMessage); \
printf("nErrorCode=%d: %s\n", nErrorCode, \
cErrorMessage); \
} else {\
printf( "Fatal Error\n"); \
} \
exit(1); \
} \
#define APIVERSION \
{\
char szVersion[255], szBuild[255];\
LSgetVersionInfo(szVersion,szBuild);\
printf("\nLINDO API Version %s built on %s\n",szVersion,szBuild);\
}\
/* main entry point */
int main()
{
APIERRORSETUP;
pLSenv pEnv;
pLSmodel pModel;
char MY_LICENSE_KEY[1024];
/*****************************************************************
* Step 1: Create a model in the environment.
*****************************************************************/
nErrorCode = LSloadLicenseString("home/li/work/tools/lindo/lindoapi/license/lndapi60.lic", MY_LICENSE_KEY);
if ( nErrorCode != LSERR_NO_ERROR)
{
printf( "Failed to load license key (error %d)\n",nErrorCode);
exit( 1);
}
......
......
......
APIERRORCHECK;
{
int nStatus;
double objval=0.0, primal[100];
/* Get the optimization result */
nErrorCode = LSgetInfo(pModel, LS_DINFO_GOP_OBJ, &objval);
APIERRORCHECK;
LSgetMIPPrimalSolution( pModel, primal) ;
APIERRORCHECK;
printf("\n\nObjective = %f \n",objval);
printf("x[0] = %f \n",primal[0]);
printf("x[1] = %f \n",primal[1]);
/* Get the linearity of the solved model */
nErrorCode = LSgetInfo (pModel, LS_IINFO_GOP_STATUS, &nStatus);
APIERRORCHECK;
/* Report the status of solution */
if (nStatus==LS_STATUS_OPTIMAL || nStatus==LS_STATUS_BASIC_OPTIMAL)
printf("\nSolution Status: Globally Optimal\n");
else if (nStatus==LS_STATUS_LOCAL_OPTIMAL)
printf("\nSolution Status: Locally Optimal\n\n");
else if (nStatus==LS_STATUS_INFEASIBLE)
printf("\nSolution Status: Infeasible\n\n");
}
/* >>> Step 7 <<< Delete the LINDO environment */
LSdeleteEnv(&pEnv);
/* Wait until user presses the Enter key */
printf("Press <Enter> ...");
getchar();
}
part of 'lindo.h' is:
/*********************************************************************
* Structure Creation and Deletion Routines (4) *
*********************************************************************/
pLSenv CALLTYPE LScreateEnv(int *pnErrorcode,
char *pszPassword);
pLSmodel CALLTYPE LScreateModel(pLSenv pEnv,
int *pnErrorcode);
int CALLTYPE LSdeleteEnv(pLSenv *pEnv);
int CALLTYPE LSdeleteModel(pLSmodel *pModel);
int CALLTYPE LSloadLicenseString(char *pszFname, char *pachLicense);
void CALLTYPE LSgetVersionInfo(char *pachVernum, char *pachBuildDate);
Thank you!
Thank you guys answering my problem. As you suggested, I need to link the library when complining. I have gotten the executable file with:
gcc -o ex_addinst ./ex_addinst.o -L/home/li/work/tools/lindo/lindoapi/bin/linux64 -m64 -llindo64 -lmosek64 -lconsub3 -lc -ldl -lm -lguide -lpthread -lsvml -limf -lirc
but there comes another problem when run the executable file ex_addinst: after run:
./ex_addinst
there comes:
./ex_addinst: error while loading shared libraries: liblindo64.so.6.0: cannot open shared object file: No such file or directory
The tricky thing is, liblindo64.so.6.0 is in the lib folder which contains:
libconsub3.so libirc.so liblindojni.so libmosek64.so.5.0 lindo.par
libguide.so liblindo64.so liblindojni.so.6.0.3 libsvml.so placeholder
libimf.so liblindo64.so.6.0 libmosek64.so lindoapivars.sh runlindo
I have created symbolic links between liblindo64.so.6.0 and liblindo64.so with
ln -sf liblindo64.so.6.0 liblindo64.so
but it doesn't help.
Can anyone tell me what is wrong here?
(I am not sure I should put this question in a new post, but I think currently it is better to follow the old one)
Ok, lindo.h contains the prototypes for those functions, but where are the functions actually defined? If they're in another C file you need to compile that one too, and link both the object files together.
If the functions are part of another static library, you need to tell the linker to link that library along with your object file.
If they're defined with a shared library, you can probably get g++ to still link to it at compile time, and take care of the library loading etc. Otherwise you'll need to load the library at runtime and reference the functions from the library. This Wikipedia article on dynamic loading of shared libraries contains some example code.
Try
g++ -Wall -o ex_addinst ex_addinst.c
instead of
g++ -Wall -o ex_addinst ex_addinst.o
You want to compile the .c file, not the .o file.
You need to tell gcc to link with the library or object file(s) that contain the LS... functions you're using. The header file tells the compiler how to call them, but the linker needs to know where to get the compiled code from.
undefined reference to ... is not a declaration problem. The compiler fails because it can't find symbols (objects) which are related to those declared functions.
In your case, you use the Limbo API, and include the header file, but you don't tell the compiler to link with the library : that's why it doesn't find symbols.
EDIT : I had forgotten the part when you say you're new to Linux. To link with the library, you need to use the -L/-l options of g++. man g++ is always a good read, and the Limbo's documentation should be, too.

Resources