mkoctfile with multiple C and C++ source files - c++

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.

Related

Having difficulties compiling simple c++ program on the command line with multiple files; maybe a linker error?

Sorry for the simple question. I am attempting to learn more c++ at a fundamental level. I have always used VS in the past, and I am trying to learn the command line and compile, navigate, etc. with it.
I started with "hello world" and was able to compile it with gcc/clang, then run it with the expected results.
I then slightly reworked this and made a new header/cpp file to do the output part of hello world, and then call that from the main function, described below:
main.cpp:
#include "MyClass.h"
int main(){
foo();
return 0;
}
MyClass.h
#pragma once
void foo();
MyClass.cpp
#include "MyClass.h"
#include <iostream>
void foo(){
std::cout << "Hello World\n";
}
I then have tried to compile with gcc and clang as follows:
clang -Wall -g main.cpp MyClass.cpp
I have tried the same with GCC, and have also tried various invocations of this, such as using -c:
clang -Wall -g -c main.cpp
clang -Wall -g -c MyClass.cpp
Each and every time, I get an error
λ clang -Wall -g MyClass.cpp main.cpp
main.cpp:13:1: error: use of undeclared identifier 'foo'
foo();
^
1 error generated.
I get this same error whether using gcc or clang.
I also tried from scratch on my laptop, to see if there was some more global issue, but I still get the same problem.
I have also tried on the basic Windows command line as well.
Other areas on StackOverflow demonstrate simple ways of compiling multiple files from the command line, and I have tried as they show, but still get errors.
I also know that "make" is something I need to learn as well, however, I just want to make sure I understand what my make file is doing before I dive into that.
I feel like it must be something trivial that I just cannot figure out.
Thank you to Andreas for the suggestion of looking at the preprocessor output. And thank you to everyone for the suggestions.
The pre-processor output did not make sense to what I was compiling.
I was using VSCode, in this case, as a text editor, making brand new files in my folder after launching it from the command line. I thought the files I created in VSCode directly into the folder (named main.cpp, for example), would produce a regular text file. However, for some reason, it did not.
Essentially, I recreated the above program in notepad and was easily able to compile it using the commands I used above. I guess VSCode may not be perfect for me as a pure text editor or I should figure out if there are settings to change to accomplish my goal.
Thank you all again for your time and consideration.
Use extern on your function. Also make sure you're compiling with c++ and not c; i.e. g++.
MyClass.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern void foo();
#ifdef __cplusplus
}
#endif

Problem with ADA file executed by a c++(UsrAppInit) in VXWorks 6.7(workspace-4)?

I have a file build and compiled correctly in ADA (a simple Hello world). I want to execute the file .o from a c++ using taskspawn. To do that I have read that you must declare in the c++ something like that:
...
#include <taskLib.h>
/* Ada binder-generated main - ADA_MAIN is passed as a macro from the makefile */
extern void ADA_MAIN(void);
void UsrAppInit()
{
int stackSize = 0x80000;
int spawnFlags = VX_FP_TASK;
/* MAIN_TASK_NAME is passed as a macro from the makefile */
char * mainTaskName = (char *) MAIN_TASK_NAME;
int priority = 100;
/* Spawn Ada environment task */
taskSpawn(mainTaskName, priority, spawnFlags, stackSize,
(FUNCPTR) ADA_MAIN, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
to complete the process I have declared the ADA_MAIN as a MACRO in makefile (in my case the makefile is makefile.mk)
(MAIN_ADA pathOfmyADAexe and MAIN_TASK_NAME "the procedure of the helloworld")
but the MACRO are not recognized in the process so I have error in compilation for MAIN_TASK_NAME and ADA_MAIN. Any suggestion about how am I missing? I could also do in different way but how?
I don’t know about your ADA_MAIN, and you don't tell us what your MACRO is, so it's a little hard to talk about them. Also, it's a while since I used VxWorks (and, then, we were supported, so had access to a cross-compiler that did the build for us: and our main program was in Ada).
That said, your problem comes down to building a program with Ada components where the main program isn't in Ada.
Ada programs need elaboration. This is the process that calls in all the components of the runtime library and arranges for them to be initialized in the right order. What components, you ask? well, for instance, there's the obvious Ada.Text_IO; and there's the less-obvious things, such as exception handling.
The elaboration code is generated using gnatbind.
Given this hello.adb
with Ada.Text_IO;
procedure Hello is
begin
Ada.Text_IO.Put_Line ("hello!");
end Hello;
you really need to supply a specification, as otherwise the compiler will generate a linker name such as __ada_hello; take control by hello.ads,
procedure Hello with
Export,
Convention => C,
External_Name => "hello";
You'll be using a cross-compilation suite. The components are prefixed by the target name, e.g. powerpc-wrs-vxworks-gnatmake, arm-eabi-gnatbind, but I'll just use the bare component name below.
$ gnatmake -c hello.adb
which generates hello.o, hello.ali (if the program was more complicated, it'd compile the closure too).
Now bind:
$ gnatbind -n -Lhello -static hello.ali
where
-n : main program not in Ada
-Lhello: adainit, adafinal renamed helloinit, hellofinal
-static: pretty sure VxWorks doesn't support shared libraries?
generating b~hello.ads, b~hello.adb (depending on the compiler release, the ~ may be replaced by e.g. double underscore). Compile:
$ gnatmake -c b~hello.adb
Now, to call from C++. you need to tell the compiler about the symbols in the Ada code, in e.g. hello.h:
extern "C" {
void helloinit();
void hellofinal();
void hello();
}
and then the main program in main.cc:
#include "hello.h"
int main() {
helloinit();
hello();
hellofinal();
}
which leaves you with the C++ compile and link, which needs the Ada runtime in libgnat.a and (for tasking) libgnarl.a, and is of course very compiler- and installation-specific: here, on the macOS host, I used
$ g++ main.cc b~hello.o hello.o /opt/gcc-8.1.0/lib/gcc/x86_64-apple-darwin15/8.1.0/adalib/libgnat.a
$ ./a.out
hello!
Translating this to the VxWorks context, I'd say that you'd call helloinit() from your main program (you probably won't need hellofinal()), and pass hello to taskSpawn() in place of your ADA_MAIN.

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.

CUDA syntax error '<'

in my test.cu file (cu file item type is CUDA C/C++)
__global__ void foo()
{
}
void CudaMain()
{
foo<<<1,1>>>();
}
and in my test.cpp file
#include "mycuda.cu"
int main()
{
CudaMain();
return 0;
}
and compilator send me error "error c2059 syntax error ' <' " in test.cu file
Inclusion of CUDA source files in a C++ file doesn't work because this simply makes the CUDA source part of the C++ program code and regular C++ compilers do not understand CUDA syntax extensions. If you still want to keep your CUDA code separate from the non-CUDA C++ code, then you might want to look into separate compilation. CUDA source code can be compiled to regular object files, that can then be linked with other object files to produce an executable.
Modify the C++ code to read:
extern void CudaMain(void);
int main()
{
CudaMain();
return 0;
}
Compile the CUDA file with nvcc, the C++ code with your C++ compiler and then link the resulting object files with nvcc (you may also need to specify the standard C++ library in the link command):
$ nvcc -c -o test_cuda.o test.cu
$ g++ -c -o test_cpp.o test.cpp
$ nvcc -o test.exe test_cuda.o test_cpp.o -lstdc++
Edit: your question is about VS2010. May be you have to create custom build steps there.
Based on the thread here: https://forums.developer.nvidia.com/t/cuda-build-error/52615/4
Your test file extension should be .cu as well, but if you're using MSCV rename does not enough you should create a new CUDA C/C++ source module in your VS project.
Also you should put spaces between the <> operators like.
foo< < <1,1> > >();
Because C++ cannot parse the <<<>>>.
I know this is an old question but I was searching around and it jogged my memory for a solution that hasn't been mentioned.
The nvcc help offers:
--x {c|c++|cu} (-x)
Explicitly specify the language for the input files, rather than letting
the compiler choose a default based on the file name suffix.
Allowed values for this option: 'c','c++','cu'.
So although it's a bit of a blunt tool, you can do:
nvcc my_source.cpp -x cu ...
and it'll compile the .cpp as if it was named .cu (ie as CUDA).

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

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?