Mixing C and C++ code yields unexpected behavior in GCC - c++

I use legacy C-Code in my current C++ project by including external headers:
extern "C" {
# include "ANN/ANN_4t70P1.h"
# include "ANN/ANN_4t70P2.h"
# include "ANN/ANN_4t70P3.h"
# include "ANN/ANN_4t70P4.h"
}
The header files look like this:
extern int ANN_4t70P1(float *in, float *out, int init);
static struct {
int NoOfInput; /* Number of Input Units */
int NoOfOutput; /* Number of Output Units */
int(* propFunc)(float *, float*, int);
} ANN_4t70P1REC = {8,3,ANN_4t70P1};
The C-Code is created by an ancient batch-file and cannot be compiled using C++ compilers. Nevertheless, this implementation works fine for Windows and Mac OS. However, when I compile the code using gcc and g++ on Linux and run the application, ANN_4t70P1REC returns incorrect values.
Are there any special linker flags that I missed out when linking the project?
Thanks!

What do you mean by:
The C-Code is created by an ancient batch-file and cannot be compiled
using C++ compilers
Are you linking using object files generated by different compilers?
If so, try to inspect your object files with:
readelf -h <objectname>
Check if there is a different ABI. If the code is generated by a very old GCC <3.3/3.4 you can have problems linking with newer versions.
Are you sure you don't have any warnings during the link?

Related

mkoctfile with multiple C and C++ source files

I am not able to have mkoctfile to successfully create an oct file that is a wrapper of some C++ function of mine (e.g. void my_fun(double*,double)). In particular my problem rises from the fact that, the wrapper code my_fun_wrap.cpp requires the inclusion of the <octave/oct.h> library which only provides C++ headers (see here), but the original code of my_fun also uses source code that is in C. E.g.
// my_fun_wrapper.cpp
#include <octave/oct.h>
#include "custom_functions_libc.h"
DEFUN_DLD(my_fun_wrapper,args, , "EI MF network model A with delays (Brunel, JCN 2000)"){
// Input arguments
NDArray xvar = args(0).array_value();
double x = xvar(0);
// Output arguments
double dy[4];
dim_vector dv (4,1);
NDArray dxvars(dv);
// Invoke my C function which also includes code in the lib file custom_functions_libc.c
my_fun(dy,x);
// Then assign output value to NDArray
for(int i=0;i<4;i++) dxvars(i) = dy[i];
// Cast output as octave_value as required by the octave guidelines
return octave_value (dxvars);
}
Then suppose that my custom_functions_libc.h and custom_functions_libc.c files are somewhere in a folder <path_to_folder>/my_libs. Ideally, from Octave command line I would compile the above by:
mkoctfile -g -v -O -I<path_to_folder>/my_libs <path_to_folder>/my_libs/custom_functions_libc.c my_fun_wrapper.cpp -output my_fun_wrapper -lm -lgsl -lgslcblas
This actually generates my_fun_wrapper.oct as required. Then I can call this latter from within some octave code, e.g.
...
...
xx = [0., 2.5, 1.];
yy = [1e-5, 0.1, 2.];
dxv = test_my_function(xx,yy);
function dy = test_my_function(xx,yy)
xx += yy**2;
dy = my_fun_wrapper(xx);
endfunction
It turns out that the above code will exit with an error in test_my_function saying that within the my_fun_wrapper the symbol Zmy_fundd is not recognized. Upon receiving such kind of error I suspected that something went wrong on the linking process. But strangely enough the compiler did not produce any error as I said. Yet, a closer inspection of the verbose output of the compiler revealed that mkoctfile is changing compiler automatically between different files depending on their extension. So my_fun_wrapper.cpp is compiled by g++ -std=gnu++11 but custom_function_libc.c is compiled by gcc -std=gnu11 and somehow the custom_function_libc.o file ensuing by this compilation process, when linked with my_fun_wrapper.o does not matches unresolved symbols.
The example above is very simplistic. In practice, in my case custom_function_libc includes many more custom C libraries. A workaround so far was to clone the .c source file for those libraries into .cpp files. But I do not like this solution very much.
How can I eventually mix C++ and C code safely and compile it successfully by mkoctfile? octave manual suggests to prepend an extern C specification (see here) which I am afraid I am not very familiar with. Is this the best way? Could you suggest me alternatively, a potential alternative solution?
So apparently the easiest solution, according to my above post is to correct the wrapper by the following preprocessor directives:
// my_fun_wrapper.cpp
#include <octave/oct.h>
// ADDED code to include the C source code
#ifdef __cplusplus
extern "C"
{
#endif
// END ADDITION
#include "custom_functions_libc.h"
// ADDED code to include the C source code
#ifdef __cplusplus
} /* end extern "C" */
#endif
// END ADDITION
...
...
This will compile and link fine.

Linking static library compiled with g++ 7.2 using gcc 3.2.3

I have an embedded application that has been written for gcc 3.2.31, and I want to link a library, written by myself, and compiled using g++ 7.2.0.
I have already built and link a test library with almost no code, but now that I am trying something more relevant, I face some issues regarding undefined symbols. Currently, I have the following kind of errors:
undefined reference to __assert_func
I do not get this error if I compile using g++ 3.2.3.
I want to use g++ 7.2.0 to have access to the new C++14 (maybe C++17) features and some new parts of the standard library (std::chrono::duration, etc.).
Is there a way to make this work?
I can fix the above issue by defining my own __assert_func:
extern "C" void __assert(const char *, int, const char *);
extern "C" void __assert_func(
const char *file, int line, const char *, const char *e) {
__assert(file, line, e);
}
...but I was wondering if there is a simpler way? In particular, there may be other name changes and I do not want to have to modify these everytime...
I assume I will not use new features that would require code that is not in the old gcc version (e.g., std::thread or std::chrono::system_clock).
Related:
Linking against an old version of libc to provide greater application coverage, with "solutions" for dynamic libraries, but no better solutions than mine for static libraries (i.e., rewriting the missing symbols).
1 The application and the library are built using the sparc-rtems gcc toolchains, and some third party tools such as JamaicaVM. I cannot simply change the toolchain used to build the main application because there are many incompatibilities with the new compiler toolchain...

Why are i2c_smbus function not available? (I2C – Embedded Linux)

There are many references to using i2c_smbus_ functions when developing embedded Linux software to communicate on the I2C bus. When i2c_smbus functions such as i2c_smbus_read_word_data are referenced in software project for ARM8 processor errors such as ‘i2c_smbus_read_word_data’ was not declared in this scope are generated at compile.
Investigation of the following header files indicate the absence of most i2c_smbus function definition.
/usr/arm-linux-gnueabi/include/linux/i2c.h
/usr/arm-linux-gnueabi/include/linux/i2c-dev.h
Also in that following reference i2c.h file has all the i2c_smbus defined.
How can this problem be resolved?
Research references
Using I2C from userspace in Linux
I2C Communication from Linux Userspace – Part II
I2C dev interface
Because you are using a wrong header file for your application.
If you see an extern on the function i2c_smbus_read_word_data() in your header, it's a header file for your kernel, but not for your application. The Linux kernel has i2c_smbus_read_word_data() and other i2c smbus functions for its internal use. But they are a) not system calls, or b) not accessible from your application.
Instead, get i2c-tools from Linux Kernel Wiki and install it. If you are using Debian, just
sudo apt-get install libi2c-dev
and use i2c_smbus_read_word_data() or any other interfaces they offer.
Version Notes
i2c-dev, untill version 3.x, used be a header only package, meaning that there was no library to link to. All functions were inline functions defined using ioctl().
e.g.)
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(file,I2C_SMBUS,&args);
}
:
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_WORD_DATA,&data))
return -1;
else
return 0x0FFFF & data.word;
}
But since v4.0, it start to be a standard shared library with libi2c.so.0 and i2c/smbus.h. You have to include the header file in your source code
#include <i2c/smbus.h>
And link libi2c.so.0 with -li2c
gcc -o a.out main.o -li2c
I ran into this today. The i2c_smbus_* functions are defined in:
/usr/include/linux/i2c-dev.h
...but when I would try to cross-compile for ARM on an older version of Ubuntu, I was running into errors such:
i2c_smbus_read_block_data was not declared in this scope
Turns out the functions are not defined in the equivalent ARM-specific location:
/usr/arm-linux-gnueabi/include/linux/i2c-dev.h
When cross-compiling, this 2nd older header file is the one used. Had to re-declare locally a few of the inline i2c_smbus_... functions to get around the problem.
Based on https://unix.stackexchange.com/questions/621854/usr-include-linux-i2c-dev-h-does-not-contain-i2c-smbus-read-word-data-functio, I have found this fixes the function not defined errors:
#include <i2c/smbus.h>
I am currently working with legacy code that references various i2c_smbus functions. It has:
#include <linux/i2c-dev-user.h>
and it fails to compile. Surely, this include used to work, but it seems the lib's header files changed at some point. I did refresh/reinstall libi2c-dev recently.
Note that I added the above include. I can't remove the original include. It is still needed.
FYI: I have not tried cross-compiling yet.
From the i2c Linux kernel documentation:
Please note that there are two files named "i2c-dev.h" out there, one is distributed with the Linux kernel and is meant to be included from kernel driver code, the other one is distributed with i2c-tools and is meant to be included from user-space programs. You obviously want the second one here.
So you need to include the i2c-dev.h from i2c-tools not from the Linux kernel.

error occured when fortran code called c code

I have used a method in a reference book about fortran codes calling c codes. The method is that if your function name in the c codes are capitalized, you may not make additional changes in your fortran code. The following is my code.
Source1.f90:
program main
implicit none
call c_subprint()
endprogram
ccode.c:
#include <stdio.h>
#include <string.h>
#ifdef _cplusplus
extern "C" {
#endif
void _stdcall C_SUBPRINT()
{
int a;
printf("%s\n","kk");
scanf("%d",&a);
}
#ifdef _cplusplus
}
#endif
The error message is that the main function cannot find out _C_SUBPRINT(LNK2019). But I have already added the .lib generated by the c code to the fortran code. And my code is almost the same as that in the reference book. what is wrong?
Different Fortran compilers generate calls differently. Many add underscores to routine names to avoid name conflicts with C-code. Its very hard to say whether or not you should exactly follow the example of an unnamed reference book. In the past, to mix Fortran and C, you have to understand some of the compiler internals. Here the Fortran compiler appears to have added an underscore to the start of the name. You could probably fix the problem by adding that in your C++ code. But that won't be portable and in principle could change with compiler versions. There is a better way: the Fortran ISO_C_Binding. This is part of the Fortran language standard and therefore standard and portable. Examples are given in the gfortran manual in the Chapter "Mixed-Language Programming" and in other questions on Stackoverflow.
From the inclusion of _stdcall I deduce you are probably using a Windows platform. Unfortunately I'm working on a Mac, so things may not be exactly the same. However, the following works for me (small changes from your code) to get a mix of Fortran and C code working together. Note - on my Mac, the gcc compiler does not include Fortran, so I used a separate Fortran compiler gfortran which I downloaded from a link at http://hpc.sourceforge.net - where instructions for installation could also be found.
program src1.f90:
program main
implicit none
call C_SUBPRINT()
endprogram
program ccode.c:
#include <stdio.h>
#include <string.h>
void c_subprint_()
{
printf("hello world!\n");
}
Note I took out the #ifdef sections - I was using pure C, so it was not needed; more importantly, note the underscore after the function name
I compiled these two modules as follows:
gcc -c ccode.c -o ccode.o
gfortran src1.f90 ccode.o -o hello
After which I can run
./hello
And get the expected output:
hello world!
Without the underscore, the linker complains about unknown symbols. There is an option in the compiler to turn off "name mangling" with the underscore. You can check your specific compiler to see how that would be done - but that's almost certainly the problem you are having.

calling C++ function from fortran not C

is it possible to call a C++ function from FORTRAN such as
#include <iostream.h>
extern "C"
{
void single_cell(void)
{
cout<<"Hi from C++";
}
}
So when I am using C it is working fine but with the C++ function it gives errors like
Undefined error to cout etc
Both g++ and gfortran, used as linkers, bring in extra libraries. That is why the Fortran/C++ combination is trickier than the Fortran/C combination ... just using the correct compiler as the linker won't work, you need to add a libary. Already suggested is to link with gfortran and specify the C++ runtime libraries. You can also link with g++ and specify the Fortran runtime libraries. See Linking fortran and c++ binaries using gcc for the details of both approaches.
Assuming you could have your Fortran code call into a C function, the problem is not the code but rather how you are linking. When you're linking C++ objects you need to also pull in the C++ runtime. If using GCC, link with the g++ command and it will pull in the parts you need.