How to compile C code that #includes C++ code? - c++

I have to compile generated C code that #includes C++ headers and it get it to work on Linux, OS X and Windows. I put the #includes myself to be able to interact with C++ code from it.
The C code however is such that a strict compiler would catch errors that could be treated as warnings. I want to pass these off as warnings as most of this is generated code which I don't have control over.
Here are my attempts to compile it (I use CMake, btw):
(I use these flags: -Wno-write-strings -Wno-error -fpermissive)
Treat the entire project as C++ code: works on Linux (with g++) but on OS X I get:
With Clang:
error: assigning to 'char *' from incompatible type 'const char *'
With g++:
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:18:no such instruction: `vmovdqa LC0(%rip), %xmm3'
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:19:no such instruction: `vmovdqa LC1(%rip), %xmm2'
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:20:no such instruction: `vmovdqu (%rsi), %xmm7'
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:21:no such instruction: `vmovdqu 16(%rsi), %xmm8'
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:22:no such instruction: `vmovdqa LC2(%rip), %xmm1'
/var/folders/hf/5dbkbqrx5p3bmnpdqqy4wgpr0000gn/T//ccvMHo2S.s:23:no such instruction: `vpshufb %xmm3, %xmm7,%xmm6'
Treat C code as C code:
Doesn't find <atomic>
fatal error: atomic: No such file or directory
#include <atomic>
Use -Wa -q flags as per this answer:
https://stackoverflow.com/a/19339870/3684931 (I made a mistake there. It should have been -Wa, -q)
Flag becomes invalid.
clang: error: unknown argument: '-q'
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
Use -Wa,-q flags as per this answer:
https://stackoverflow.com/a/19339870/3684931
Flag is still invalid.
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
clang: error: unsupported argument '-q' to option 'Wa,'
How do I go about building this?

You seem to be solving this problem backwards, to me. Every conforming C++ implementation seems to have a compatible C ABI, so C++ projects can use C libraries. Use that to your advantage.
Create C libraries containing your C code, and compile them as C code (e.g. cc -c your_filename.c will produce a your_filename.o object file).
Create a C++ project (where you should be able to include all of your C headers, if you design them carefully), and use your linker to link to the your_filename.o object files you produced in step 1, when compiling that project.

I put the #includes myself to be able to interact with C++ code from it.
This is where you went wrong. #includeing a C++ header from a .c file will never work.
Instead, you need to make header files which are compatible with both C and C++. These files should only contain code in the common subset of C and C++ ; and they should also contain:
#ifdef __cplusplus
extern "C" {
#endif
// main header code here
#ifdef __cpluscplus
}
#endif
so that the C++ units including this header create calls using the C ABI.
In this header , you can declare some functions that will do the interacting with the C++ code which your C files require. And you can implement those functions in a new C++ source file which you write.

Related

Using POSIX feature test macros with C++

When I'm building POSIX C programs, I want to be portable and use only POSIX or standard C library functions. So, for example, with gcc or clang, I build like this:
gcc -std=c99 -D_XOPEN_SOURCE=600
Setting the standard to C99 removes all extensions, then _XOPEN_SOURCE exposes POSIX interfaces. I no longer have the environment polluted with extensions from GNU, BSD, etc.
However, the waters seem murkier with C++. I want to do this:
g++ -std=c++14 -D_XOPEN_SOURCE=600
This has worked fine for me on various operating systems: Linux/glibc, Haiku, MinGW, macOS, at least. But apparently, there are problems with POSIX feature test macros and C++. Oracle docs have this to say:
C++ bindings are not defined for POSIX or SUSv4, so specifying feature test macros such as _POSIX_SOURCE, _POSIX_C_SOURCE, and _XOPEN_SOURCE can result in compilation errors due to conflicting requirements of standard C++ and these specifications.
While I don't have a copy of Oracle Solaris, I am seeing issues with FreeBSD and OpenBSD.
On FreeBSD:
#include <iostream>
int main() { }
$ clang++ -std=c++14 -D_POSIX_C_SOURCE=200112L t.cpp
In file included from t.cpp:1:
In file included from /usr/include/c++/v1/iostream:37:
In file included from /usr/include/c++/v1/ios:215:
/usr/include/c++/v1/__locale:631:16: error: use of undeclared identifier 'isascii'
return isascii(__c) ? (__tab_[static_cast<int>(__c)] & __m) !=0 : false;
...
(This builds fine with _XOPEN_SOURCE=600). C++ headers on FreeBSD use isacii, a non-standard function, so it's not exposed when _POSIX_C_SOURCE is set.
Or on OpenBSD:
#include <fstream>
int main() { }
$ clang++ -std=c++14 -D_XOPEN_SOURCE=600 t.cpp
In file included from t.cpp:1:
In file included from /usr/include/c++/v1/fstream:183:
In file included from /usr/include/c++/v1/ostream:138:
In file included from /usr/include/c++/v1/ios:215:
In file included from /usr/include/c++/v1/__locale:32:
In file included from /usr/include/c++/v1/support/newlib/xlocale.h:25:
/usr/include/c++/v1/support/xlocale/__strtonum_fallback.h:23:64: error: unknown type name 'locale_t'
char **endptr, locale_t) {
Presumably <locale.h> isn't getting included somewhere it “should” be.
The worrisome conclusion I'm drawing is that you can't portably have a POSIX C++ environment that is free of non-POSIX extensions. These examples work fine on OpenBSD and FreeBSD if the feature test macros are removed. That looks to be because the BSD headers expose BSD functions unless in standard C mode, but they do not care about standard C++ mode (they explicitly check whether macros corresponding to C89, C99, or C11 are set). glibc looks to be the same: it still exposes non-standard C functions in standard C++ mode, so perhaps it's only a matter of time before I run into a build error there.
So the actual question is this: can you write portable POSIX C++ code which does not expose platform-specific functionality? Or if I'm targeting POSIX with C++ should I just not set any feature test macros and hope for the best?
EDIT:
I got to thinking about the implications of this (as in, why do I care?), and the following program, I think, illustrates it. This is Linux/glibc:
#include <ctime>
int dysize;
$ g++ -c -std=c++14 t.cpp
t.cpp:2:5: error: ‘int dysize’ redeclared as different kind of entity
2 | int dysize;
| ^~~~~~
In file included from t.cpp:1:
/usr/include/time.h:262:12: note: previous declaration ‘int dysize(int)’
262 | extern int dysize (int __year) __THROW __attribute__ ((__const__));
This is the standard <ctime> header, which is does not include anything called dysize. That's an old SunOS function that glibc includes for compatibility. A C program built with -std=c99 won't expose it, but C++ always does. And there's no real way of knowing which non-reserved identifiers will be used by various implementations. If -std=c++14 caused non-standard identifiers to be hidden, that would avoid this problem, but it doesn't, and I can't see a way around that.
Which might imply that the feature test macro is a red herring: the source of the problem is that, on at least some real-world implementations, C++ compilers are exposing symbols they're not supposed to.
My suggestion is to build a toolchain, and work from that with the libraries, includes, the correct compiler (perhaps a stripped version that can only use POSIX libraries, includes, etc).
To make it portable, generally you would build the application using static linkers. Other linker options may be necessary that point specifically or include your toolchain environment paths.
And if you're using POSIX threads, you may need -pthread.
I see that you are using system-wide headers and libraries, when really, you probably want a specific to your POSIX application toolchain, to avoid contamination.

Can't compile any c++ file

I have this simple file, called lol.c
#include <iostream>
using namespace std;
int main() {
return(0);
}
From terminal, i type g++ lol.c
This is the output:
In file included from /usr/include/wchar.h:36:0,
from /usr/include/c++/4.9/cwchar:44,
from /usr/include/c++/4.9/bits/postypes.h:40,
from /usr/include/c++/4.9/iosfwd:40,
from /usr/include/c++/4.9/ios:38,
from /usr/include/c++/4.9/ostream:38,
from /usr/include/c++/4.9/iostream:39,
from lol.c:1:
/usr/include/stdio.h:30:22: fatal error: SDL_main.h: File o directory non esistente
#include "SDL_main.h"
^
compilation terminated.
I don't know if the problem is something with SDL, but when i try to run ../configure to install it, i have this:
configure: error: cannot run C compiled programs.
See `config.log' for more details
If is this needed, i can put config.log file too.
There are multiple problems:
you gave a .c extension to a C++ source file; that is wrong, C++ files should have a .cpp (or .cxx, .C, .c++, the last two are a bit frowned upon) extension, or the compiler may try to compile it as C code;
you are invoking gcc instead of g++; this is wrong too, calling gcc on C++ files misses several options required to compile and link correctly (including, but not limited to, linking against the C++ standard library); that was in an older revision of the question, now it says g++;
but most importantly, your build environment is completely broken (some would say "FUBAR"); it is not normal that /usr/include/stdio.h includes stuff from SDL (the fact that it cannot be found is just a minor incident compared to this); you should really purge and reinstall anything related to gcc and to the headers of the C library; look for some libc6-dev package (or similar) to reinstall (be careful not to mess with the C library proper, or your system may be rendered essentially unbootable).
You can't give .c (c extension) to a c++ file.
1 - Change it to .cpp (c++ extension, lol.cpp)
2 - You have to give options to g++ (in your case use -o to create executable file) g++ lol.cpp -o nameofyourprogram
3 - Execute through your terminal ./nameofyourprogram

C++ GNU GCC with #define out & colliding

I am working with Code::Blocks and C++ GNU GCC and trying to port my Visual Studio Project to GNU GCC.
And while I am trying to compile I get stuck with my define macro from a Defines.h file:
#define out &
And when compiling I get this error:
error: expected unqualified-id before '=' token
On this line:
// Open for output. Default for #c ofstream and fstream.
static const openmode out = _S_out;
In ios_base.h
As I know, that file is a part of a libstd library. Can I disable it? If so, how can I do that?
My library doesn't requiring any std c++, just c library.
There are two main options:
Don't define a macro using the word out.
Declare the macro after you include all of your headers.
But seriously, a macro named out that becomes & is a pretty awful macro. It's going to make it difficult to understand the code very quickly.

How configure include path and use standard library with gcc compiler?

I know this topic was few times there, but I can't get satisfactory answer.
C:\Users\Krzysiek>gcc test.c
test.c:3:20: fatal error: iostream: No such file or directory
compilation terminated.
This is what I try to do
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
Simple program with "include"
I've heard of LIBRARY_PATH. So I've setted that. Still this same error I have.
GCC provides wrappers around calling its various compilers.
You are using gcc, which is for C (and consequently will not include or link the C++ standard library; the compiler would go on to complain about the rest of your code, too, since it's not valid C);
Use g++, which is for C++.
Also try to use a conventional extension for C++ source files, which is .cc, .cxx or .cpp.
Use g++ instead: it will link to the c++ standard library.
When you use the gcc command, gcc looks at the file extension to decide which language to use to compile. As you used a .c file, gcc will switch by default to C.
# Use the C compiler
gcc test.c
# Use the C++ compiler
gcc test.cpp
To choose a different language, you can use the -x option:
# Use the C++ compiler even if the extension is .c
gcc -xc++ test.c
Another method of using the C++ compiler is to use g++ in the command line. This is the preferred way, as it links with the correct libraries.
# Use the C++ compiler
g++ test.c

Cygwin gcc compiled fails in IDE complaining about 'exit' undeclared

When I compile a program using just
gcc code.c
There are no messages, and an output file is generated successfully. The outputted file works. However, when I try to the same cygwin installation's gcc compiler in an IDE (I've tried Netbeans and Dev-C++), I get the following errors
main.cpp:27: error: `exit' undeclared (first use this function)
main.cpp:27: error: (Each undeclared identifier is reported only once for each function it appears in.)
main.cpp:77: error: `write' undeclared (first use this function)
main.cpp:78: error: `close' undeclared (first use this function)
I don't see what's different. Why does it not compile?
OK, the issue was that in the IDE, the file had a .cpp extension, whereas when I was compiling from a terminal, it had a .c extension. So, my new question is why does it not compile when it's treated as a c++ file. Isn't C a subset of C++?
C++ is stricter then C. Where C allows you to call a function without a prototype, C++ does not allow this.
To solve the problem, you want to add:
#include <stdlib.h>
Also, when compiling at the command line. Make sure to use the -Wall flag so you'll get important warnings:
gcc -Wall code.c
The IDE is using fussier options to the compiler. You need to include some headers:
#include <stdlib.h> // exit()
#include <unistd.h> // close(), write()
The default options allow almost anything that might be C to compile. By the looks of it, the IDE sets '-Wmissing-prototypes' as one of the compiler options.
If you compile code with a C++ compiler, you must ensure that all functions are declared before use. C is sloppier (or can be sloppier) about that - it is recommended practice to ensure all functions are declared before being defined or referenced, but it is not mandatory. In C++ it is not optional.
There is a subset of C that is also a subset of C++; there are bits of C that are not C++, and there are many bits of C++ that are not C. In particular, an arbitrary C program is not, in general, a C++ program. For example, a C program may not declare 'exit()' and yet it can both use it and still compile. A C++ program must declare 'exit()' before it can user it and compile.
You will have to use g++ for compiling .cpp files.
One possible reason may be that the IDE is unable to access the include files, the cygwin gcc compiler may be expecting it in /usr/include(not sure), and the dev-cpp may not be able to access it.