linking objective c++ - c++

I am trying to figure out why when I convert my main.m file to a main.mm file, it no longer will link properly.
I have reduces the problem to the following example code:
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}
I am using gnustep and linux. I enter the following commands and everything works as expected:
g++ -g -c main.m -I/usr/GNUstep/Local/Library/Headers -I/usr/GNUstep/System/Library/Headers
g++ -g -o test main.o -L/usr/GNUstep/Local/Library/Libraries -L/usr/GNUstep/System/Library/Libraries -lgnustep-base -lgnustep-gui
Now if I rename main.m to main.mm and use these two commands ( same exept main.m now main.mm):
g++ -g -c main.mm -I/usr/GNUstep/Local/Library/Headers -I/usr/GNUstep/System/Library/Headers
g++ -g -o test main.o -L/usr/GNUstep/Local/Library/Libraries -L/usr/GNUstep/System/Library/Libraries -lgnustep-base -lgnustep-gui
I get the following error:
main.mm:7: undefined reference to `NSApplicationMain(int, char const**)'
Can someone please find what I am doing wrong? I do not see why it is now failing to link.
I am trying to add some C++ classes to an objective c program and this is preventing me from continuing.
Thank you for any help you can provide.

The problem is that when you compile it as C++, the compiler mangles the name of the symbol NSApplicationMain, so it can't find it, since it's looking for something like __Z17NSApplicationMainiPPKc. You can use the nm program (from binutils) to see what symbols the object files are referencing:
$ # When compiled as Objective-C:
$ nm main.o | grep NSApplicationMain
U NSApplicationMain
$ # When compiled as Objective-C++:
$ nm main.o | grep NSApplicationMain
U _Z17NSApplicationMainiPPKc
In order to avoid this problem, C functions need to be declared with an extern "C" modifier in order to tell the compiler not to mangle the name. Looking into <AppKit/NSApplication.h>, the header file where NSApplicationMain is declared, I see this:
APPKIT_EXPORT int
NSApplicationMain(int argc, const char **argv);
Alas, APPKIT_EXPORT is defined to be one of extern, __declspec(dllexport), extern __declspec(dllexport), or nothing in <AppKit/AppKitDefines.h>. Since it's also used for global variable declarations, we can't get around this by redefining it to extern "C" (which would be extremely hacky and kludgy anyways). The AppKit header files do not seem to contain any extern "C" declarations at all, although I do see them in various header files under Foundation/ and GNUStepBase/.
So what can you do? The solution is to wrap your includes with an extern "C":
extern "C"
{
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}
This will give the functions defined in those header files the proper linkage, and it will all work out. But you shouldn't have to do this -- I would file a bug report with GNUstep, telling them to add proper extern "C" declarations to their header files.

The problem is the name mangling c++ compilers typically use to enable function overloading at the link stage.
C++ defines a extern "C" directive that forces it to use a C compatible name for a function.
You can use it in a C++ file like so :-
// this makes func use a C compatible linkage
extern "C" void func(int a)
{
In a header file that is included by C and C++ it is necessary to protect the extern "C" declaration from C, and the C compiler does not under stand it.
#ifndef EXTERN_C
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
#endif
// Use it like this to declare a Function with C linkage
EXTERN_C void func(int a);
// If you have a lot of functions and declarations that need to be C compatible
#ifdef __cplusplus
extern "C" {
#endif
//functions with C linkage
void func(int a);
...
#ifdef __cplusplus
}
#endif
Now, how does this help your problem? Well, main.mm means the Foundation.h and AppKit.h files are being compiled as C++. Why Apple have not protected NSApplicationMain with a extern "C" directive I cannot guess, but it clearly isn't guarded.
A simple, if brutal, fix would be to alter your #imports like follows:
extern "C" {
// All declarations inside this block will use C linkage
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}

Related

Namespace resolution inside preprocessor

I have a .h header shared among a C executable and a large C++ codebase.
#ifdef __cplusplus
namespace my {
#endif
typedef int my_t;
#define MY_OH_MY sizeof(my_t)
typedef my_t alias_t;
// plenty of other typedefs which push me to keep only
// these two bracing #ifdef __cplusplus ...
#ifdef __cplusplus
} // namespace
#endif
The C source works well with the exclusion.
#include "my.h"
int main(int argc, char ** argv)
{
my_t m = 1;
alias_t a = 2;
m += MY_OH_MY;
return 0;
}
However the CXX source fails under Gnu compiler:
#include "my.h"
int main(int argc, char ** argv)
{
my::my_t m = 1;
my::alias_t a = 2;
m += MY_OH_MY;
return 0;
}
my.h:7:25: error: ‘my_t’ was not declared in this scope; did you mean ‘my::my_t’?
7 | #define MY_OH_MY sizeof(my_t)
Basically because (?) at preprocessor time are namespace still not a thing ?
I was expecting that in any case it would have fallen within the namespace { } enclosing group.
I can surely change it to the following, but I still cannot figure out why it doesn't work.
#ifdef __cplusplus
#define MY_OH_MY sizeof(my::my_t)
#else
#define MY_OH_MY sizeof(my_t)
#endif
You cannot use namespaces (as it is not a feature of C language) in C identifiers that must be accessed from C. Indeed, you must declare those specially in order for the compiler not to mangle the names. You can only use them in C++, but be carefull as to share code with C, you must inform the C++ compiler which routines and what identifiers will be visible from C (the compiler mangles the names in a different way to include info about operator definitions, parameter lists and overloading, and namespaces) resulting in identifiers completely cryptic to the programmer.
To see an example, just write this function:
char *function1(char *parameter1, int parameter2)
{
return 0;
}
and compile it as C language (naming the file with .c suffix) and with C++ language (using .cc as file suffix). Then use nm(1) to see the names the compiler used to name your function.
###As C code (in file func.c):
$ make func.o
cc -O2 -pipe -c func.c -o func.o
$ nm func.o
0000000000000000 T function1
$ _
###Now as C++ code (in file func.cc):
$ make func.o
c++ -O2 -pipe -c func.cc -o func.o
$ nm func.o
0000000000000000 T _Z9function1Pci
$ _
The _Z indicates something to the compiler, the 9 indicates an identifier 9 characters long (function1), The P is for a pointer, c is for char and i if for integer parameters.
If you have compiled it in C++, but declared it inside an extern "C" { } block, then the name would have been the same as in the first example, but you should not be able to define another function with name function1 and different parameter list, as there's already a C function named function1:
#ifdef __cplusplus
extern "C" {
#endif
/* C++ functions that will be accessible from C code, or C function
* declarations that will be accessed from C++ code, depending on which
* source you include this code */
#ifdef __cplusplus
} /* extern "C" */
#endif

Automatically modifying C library to be used by C++

I'd like to make a tool that automatically wraps C libraries in:
#ifdef __cplusplus
extern "C" {
#endif
But I'm confused by what exactly needs to be wrapped with extern "C", and what needn't be. Only functions? What about any (shock-horror) global variables? Anything else?
If I write a script that just finds all functions and wraps them with extern "C", is that enough?
And finally: if the library already wrapped its functions with extern "C" and then they're wrapped again, can I trust that nothing bad happens and it'll still work fine, or do I need to explicitly check for this?
It does not matter, because anything that does not need it (such as macros and comments) will be unaffected by it, so you can just wrap the entire header content - and that hardly requires a a "tool".
Also not this is not "modifying the library", just modifying the header.
Nested wrapping is benign - applying C linkage to something that already has it has no effect.
What extern "C" does is tell the C++ compiler not to apply name mangling to the specified symbol because it has C linkage and the corresponding name in the library has C linkage and is not name-mangled.
Name-mangling is the means by which C++ applies meta-data to a symbols in order to provide type information and parameter counts in order to support C++ features that require this information such as function overloading.
See this answer here which is partially related.
You'll basically just want to either:
Autowrap an include, i.e. extern "C" { #include <foo.h> }
Autowrap the C header files being included by the include (so, at the start of "foo.h" as opposed to the include statement itself)
As far as doubly-wrapped extern "C"s, I tested it with these files:
lib.h:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void printHWorld(void);
#ifdef __cplusplus
}
#endif
lib.c:
#include <stdlio.h>
#include <lib.h>
void printHWorld(void) {
printf("Hello, world!\n");
}
main.cpp:
#ifdef __cplusplus
extern "C" {
#endif
#include <lib.h>
#ifdef __cplusplus
}
#endif
int main(void) {
printHWorld();
return 0;
}
I then built it with the following commands:
gcc -Wall -O2 -I. -o lib.o -c lib.c
g++ -Wall -O2 -I. -o main.o -c main.cpp
g++ -o test main.o lib.o
And that worked just fine, so I don't think you need to worry about the double extern "C"

Call a C function from C++ code

I have a C function that I would like to call from C++. I couldn't use "extern "C" void foo()" kind of approach because the C function failed to be compiled using g++. But it compiles fine using gcc. Any ideas how to call the function from C++?
Compile the C code like this:
gcc -c -o somecode.o somecode.c
Then the C++ code like this:
g++ -c -o othercode.o othercode.cpp
Then link them together, with the C++ linker:
g++ -o yourprogram somecode.o othercode.o
You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function. So othercode.cpp begins with:
extern "C" {
#include "somecode.h"
}
somecode.h should contain something like:
#ifndef SOMECODE_H_
#define SOMECODE_H_
void foo();
#endif
(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.)
Let me gather the bits and pieces from the other answers and comments, to give you an example with cleanly separated C and C++ code:
The C Part:
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
void foo(void)
{
/* ... */
}
Compile this with gcc -c -o foo.o foo.c.
The C++ Part:
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
void bar() {
foo();
}
Compile this with g++ -c -o bar.o bar.cpp
And then link it all together:
g++ -o myfoobar foo.o bar.o
Rationale:
The C code should be plain C code, no #ifdefs for "maybe someday I'll call this from another language". If some C++ programmer calls your C functions, it's their problem how to do that, not yours. And if you are the C++ programmer, then the C header might not be yours and you should not change it, so the handling of unmangled function names (i.e. the extern "C") belongs in your C++ code.
You might, of course, write yourself a convenience C++ header that does nothing except wrapping the C header into an extern "C" declaration.
I agree with Prof. Falken's answer, but after Arne Mertz's comment I want to give a complete example (the most important part is the #ifdef __cplusplus):
somecode.h
#ifndef H_SOMECODE
#define H_SOMECODE
#ifdef __cplusplus
extern "C" {
#endif
void foo(void);
#ifdef __cplusplus
}
#endif
#endif /* H_SOMECODE */
somecode.c
#include "somecode.h"
void foo(void)
{
/* ... */
}
othercode.hpp
#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE
void bar();
#endif /* HPP_OTHERCODE */
othercode.cpp
#include "othercode.hpp"
#include "somecode.h"
void bar()
{
foo(); // call C function
// ...
}
Then you follow Prof. Falken's instructions to compile and link.
This works because when compiling with gcc, the macro __cplusplus is not defined, so the header somecode.h included in somecode.c is like this after preprocessing:
void foo(void);
and when compiling with g++, then __cplusplus is defined, and so the header included in othercode.cpp is now like that:
extern "C" {
void foo(void);
}
This answer is inspired by a case where Arne's rationale was correct. A vendor wrote a library which once supported both C and C++; however, the latest version only supported C. The following vestigial directives left in the code were misleading:
#ifdef __cplusplus
extern "C" {
#endif
This cost me several hours trying to compile in C++. Simply calling C from C++ was much easier.
The ifdef __cplusplus convention is in violation of the single responsibility principle. A code using this convention is trying to do two things at once:
(1) execute a function in C
-- and --
(2) execute the same function in C++
It's like trying to write in both American and British English at the same time. This is unnecessarily throwing an #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else a useless tool which makes the code harder to read #endif into the code.
For simple code and small libraries the ifdef __cplusplus convention may work; however, for complex libraries it is best to pick one language or the other and stick with it. Supporting one of the languages will take less maintenance than trying to support both.
This is a record of the modifications I made to Arne's code to get it to compile on Ubuntu Linux.
foo.h:
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
foo.c
#include "foo.h"
#include <stdio.h>
void foo(void)
{
// modified to verify the code was called
printf("This Hello World was called in C++ and written in C\n");
}
bar.cpp
extern "C" {
#include "foo.h" //a C header, so wrap it in extern "C"
}
int main() {
foo();
return(0);
}
Makefile
# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'
myfoobar: bar.o foo.o
g++ -o myfoobar foo.o bar.o
bar.o: bar.cpp
g++ -c -o bar.o bar.cpp
foo.o: foo.c
gcc -c -o foo.o foo.c

trouble using c library in c++

To teach myself a little C++, I decided to write a little Program to write text to my Saitek X52 Pro joystick display.
I wanted to use Eduards C-library
http://plasma.hasenleithner.at/x52pro/
I know I have to place an "extern C" around the methods if I want to use them in my C++ program. But that means changing the Header file of the library - and then it wouldn't build anymore.
What would be the correct approach in this case?
EDIT: the suggested method worked partially.
Comm.cpp:
...
extern "C"{
#include <x52pro.h>
}
using namespace std;
int main ( int argc, char *argv[] ) {
cout<<"entered main"<<endl;
char *String;
strcpy(String,"testing");
struct x52 *hdl = x52_init();
x52_settext(hdl, 0,String , 7);
x52_close(hdl);
return EXIT_SUCCESS;
}
Error Message:
Comm.o: In function `main':
Comm.cpp|38| undefined reference to `x52_init'
Comm.cpp|39| undefined reference to `x52_settext'
Comm.cpp|40| undefined reference to `x52_close'
which are all methods defined in x52pro.h
To use extern "C" in C header files, wrap it so
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
or you can wrap the #includes with extern "C"
extern "C" {
#include <chdr1.h>
#include <chdr2.h>
}
When linking your application, you must tell the linker what library to use and where the library is. From your link, you must add libusb as well. This looks roughly like this
g++ -o app_name Comm.o -L /path/to/library -lx52pro -lusb
When the library is installed in the system lib directory, you can omit the -L /path/... part. If you use a Makefile, you define this in some variables, usually
LDFLAGS = -L /path/to/library
LDLIBS = -lx52pro -lusb
See also Compiling and Linking and Wikipedia - Linker (computing)
In your C++ code, you can surround the included header file with extern "C" like this:
extern "C" {
#include "c_header_file.h"
}
Then, you would not need to modify the header file of the third party library.
#ifdef __cplusplus
extern C {
#endif
...
#ifdef __cplusplus
}
#endif

How to link app with static library + why this is not working

I have a problem. I wrote example code and I want to build it without the error:
main.cpp(.text+0x5): undefined reference to `test()'
Library
test1.c
#include <stdlib.h>
void test()
{
puts("Działa");
}
test1.h
#ifndef TEST1_H
#define TEST1_H
extern void test();
#endif
makefile
all:
gcc -c ./src/test1.c -o ./lib/test1.o
ar rcs ./lib/libtest1.a ./lib/test1.o
Program
main.cpp
#include <test1.h>
int main()
{
test();
return 0;
}
makefile
all:
g++ -static -I../test1/include -L../test1/lib ./src/main.cpp -o ./build/MyApp -ltest1
What am I doing wrong?
You are compiling a C code function, but you are expecting to link a C++ function.
Because of 'type safe linkage', the function you provide is not the function that the C++ code calls.
Either in test1.h use:
#ifdef __cplusplus
extern "C" {
#endif
extern void test1(void);
#ifdef __cplusplus
}
#endif
Or:
Compile the function with the C++ compiler.
The C++ compiler will mangle the symbol names to provide type-safe linkage (a term which you should be able to search for via your preferred search engine).
The 'compiler' - actually the linker - is looking for a function with a C++ mangled name representing the C++ function with the signature 'void test1(void);'.
For example (but remember - different compilers deliberately mangle things differently), G++ 4.2.1 on MacOS X 10.6.2 generates a symbol '__Z5test1v' for the function; GCC generates a symbol '_test1'. Clearly, when the linker is looking for '__Z5test1v', the symbol '_test1' is not going to be used - it is not spelled the same. This is a good thing.
You can use 'nm -g' on the object file for the main program to see what it is looking for, and on the object file in the library to see what it is providing. And, given that the spellings are different, that is why the loader does not pick up the library function - it is looking for something with a different name.
You are calling a C function from a C++ function. The naming between the two is different (C++ mangles names to include parameter information).
Change the header file to look like this:
#ifdef __cplusplus
extern "C" {
#endif
extern void test();
#ifdef __cplusplus
}
#endif
This will tell the compiler that the function follows the C naming/calling convention.