I've been creating a UI toolkit to use on MacOS and Windows, but im currently working and testing the MacOS side of things. Recently, when im compiling my code, using CMake, I get an unreasonable amount of errors from including the Cocoa header. Here is a ghostbin of the errors.
I'm not sure if this is a complete answer to your question, but hopefully it gives you a path forward. Thanks to #uliwitness for mentioning #if __OBJC__.
So QT5 has a git repo for qmacextras, which combines c++ and objective-c, something I am doing and how I was seeing a bunch of errors when importing <Foundation/Foundation.h> or <Cocoa/Cocoa.h>. Looking at some of their code, I saw this:
// ### remove when merged to QtCore
/*!
* \macro Q_FORWARD_DECLARE_OBJC_CLASS(classname)
*
* Forward-declares an Objective-C class name in a manner such that it can be
* compiled as either Objective-C or C++.
*
* This is primarily intended for use in header files that may be included by
* both Objective-C and C++ source files.
*/
#ifdef __OBJC__
#define Q_FORWARD_DECLARE_OBJC_CLASS(classname) #class classname
#else
#define Q_FORWARD_DECLARE_OBJC_CLASS(classname) typedef struct objc_object classname
#endif
and
// Put in your header file
Q_FORWARD_DECLARE_OBJC_CLASS(NSData);
Q_FORWARD_DECLARE_OBJC_CLASS(NSImage);
// etc
https://code.qt.io/cgit/qt/qtmacextras.git/tree/examples/macextras/macfunctions?h=5.14
Using this might negate those errors.
You're not really asking a question... but from a casual glance at what little information you provide, it looks like there is ObjC code being run through a non-ObjC compiler.
This usually happens when someone includes an ObjC header from a C or C++ source file. A very common way of causing this is to add a precompiled header to your project that includes Cocoa/Cocoa.h. A precompiled header is used for all C-descended languages you compile, so also for C or C++ files.
To avoid ObjC-specific code from being included in non-ObjC files, wrap it in #if __OBJC__ preprocessor macros. (This also applies to C++ code in your precompiled header, which you'll want to wrap in #if __cplusplus)
Related
In an iOS Swift project I'm including a set of libraries built using C++ (HikVision/hcnetsdk.h) and while I've managed to get the frameworks to build, the header file won't compile and Xcode is giving me multiple 'C does not support default arguments'.
For example on this line:
NET_DVR_API BOOL __stdcall NET_DVR_SetConnectTime(DWORD dwWaitTime = 3000, DWORD dwTryTimes = 3);
I've checked the build settings of the project and as far as I can tell everything is set to use C++, so I'm confused as to why Swift is compiling this as C, and complaining about default arguments.
My bridging header file is as follows:
#import "ldapTest.h"
#import "hcnetsdk.h"
#import "HikDec.h"
I'm fairly sure it's a build setting somewhere but which one I don't know.
So it turns out you can't include a C++ header file which contains C++ specific keywords into a Swift bridging header file.
What I did manage to do for my specific situation was find a "C" replacement of the "C++" header which worked with a few minor tweaks.
This is the "C" header file for the HikVision HCNetSDK.h which I found online:
https://github.com/shulianghe/new-project/blob/master/pro/hcSrc/incCn/HCNetSDK.h
If anyone has a similar problem with other C++ header files, you can copy some of the #ifdef __cplusplus statements in the link above to see how it's done.
So I'm currently working on something that uses OpenCL. The OpenCL spec provides the users with a directive which must be included before the inclusion of the header (cl.h)
#define CL_TARGET_OPENCL_VERSION 110
Which basically defines the version they want to use. Suppose I'm making a library and I want my users to define this instead of me defining this inside my files. What I did was.
-----main.cpp---
#define CL_TARGET_OPENCL_VERSION 110
#include "library.h"
-------x---------
----library.h-----
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
And the compiler prints both def and ndef messages. And the OpenCL library also throws a warning that it's undefined. I thought that the library header would get substituted into main and it'd only print the def message. Is there anything I understood wrong?
I'm particularly confused as to where does the preprocessor start? If it starts from main.cpp and goes from top to down, then it surely has defined the macro. After that it sees the library inclusion, then it should only print the def message but it prints both.
This leds me to believe the preprocessor does scan the header file before including it in main? Dunno the reason why. Also I have assured that the library header isn't included elsewhere.
One interesting thing I noticed was, if i did this
-----helper.h---
#define CL_TARGET_OPENCL_VERSION 110
-------x---------
----library.h-----
#include helper.h
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
It prints the def message "twice". If anybody can explain all this I'd be grateful.
EDIT:- The files I'm compiling are main.cpp library.h and library.cpp
Library.cpp includes library.h from the start as usual. Maybe this other cpp is causing the problem?
In C/C++ programs, the compiler handles each .c and .cpp file separately.
The compilers build each source file (NOT the header files, only .c and .cpp files) independently from each other (this source files are called compilation unit).
Thus, when your main.cpp is built, the compiler finds the #define CL_TARGET_OPENCL_VERSION 110 you have added on top of the main.cpp file, emiting the defmessage.
But when the compiler builds the library.cpp file, it does not find the version define, so it emits the ndef message.
So, following this explanation, it is completely normal that in your last case, when you add the define to the .h file, the compiler emits the def message twice, once for the main.cpp file and once for the library.cpp file.
Now, the problem is where should you add the define, in order to have the program built consistently, with the same version for all the .cpp files.
Usually, all the IDEs have some configuration page where you can add global defines, for all the project, which are "inserted" into all the compilation units before everything else. So when the IDE calls the compiler, it passes the same defines to all the compilation units. You should add this kind of defines in this page.
In your IDE (I am using Code::Blocks, v 17.12), you can find this page in the menu: Project / Build Options
For each type (Debug or Release), you have to go to the tab Compiler Settings, and there to the sub tab #defines. There you can add global defines, which can be different if you are building in Debug or in Release mode (of course, if you set the same in both modes, they would be the same).
Once you have added your define here, please, remove it from the main.cpp, library.h and any other place where you may have added it, in order to avoid duplicities.
From the comments about portability:
You have several options:
Always use Code::Blocks: this would be the easiest way, since you can pass the Code::Blocks project along with the source files, and everything would be already setup.
Use cmake, which is a script build system, where you can set defines and so in the same way as using an IDE. cmake is much widely used than Code::Blocks, so maybe it is a better option.
Add a new options.h header file, where you set all the defines, and include it to all your .c/.cpp. This setup has the additional benefit that for different systems, changing only the options.h file the build can be completely different. This is a manually setup of what the IDE is doing. It has the advantage that does not rely on external tools, but the disadvantage that you have to remember to add it in all the new .cpp files added to the project.
My recommendation is go with cmake, just as the others have said.
Prefer using #ifndef XXXX_h #define XXXX_h #endif over #pragma once
If your #include search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h and b/foo.h), so a #pragma once in one of them will suppress both. It may also be unable to tell that two different relative includes (e.g. #include "foo.h" and #include "../a/foo.h" refer to the same file, so #pragma once will fail to suppress a redundant include when it should have.
This also affects the compiler's ability to avoid rereading files with #ifndef guards, but that is just an optimization. With #ifndef guards, the compiler can safely read any file it isn't sure it has seen already; if it's wrong, it just has to do some extra work. As long as no two headers define the same guard macro, the code will compile as expected. And if two headers do define the same guard macro, the programmer can go in and change one of them.
#pragma once has no such safety net -- if the compiler is wrong about the identity of a header file, either way, the program will fail to compile. If you hit this bug, your only options are to stop using #pragma once, or to rename one of the headers. The names of headers are part of your API contract, so renaming is probably not an option.
(The short version of why this is problematic to use #pragma is that neither the Unix nor the Windows filesystem API offer any mechanism that guarantees to tell you whether two absolute pathnames refer to the same file.)
Referred Question: Problem when #import C++ Header File in iPhone/iPad Project
Well, my project is relatively huge and cannot solve that either changing ALL or PART OF my project files .m to .mm or changing the ALL or PART OF file types in File Inspector.
That is because both my colleagues and library authors DOES NOT follow the C++ standard strictly, such as assigning void* to int* and other various violations. Objective C would allow these and just gives warnings.
The C++ header file I want to #import is a library. It uses keyword namespace in its header, while its implementation is in an .a assembly file. That means it is nearly impossible to hack them. Besides that, my project also includes other libraries that are compatible only with Objective C.
Does anyone know how to solve this?
The ways I could imagine is as follows:
Find an alternative for namespace, but still I want to write
codes like QCAR::Renderer in my project.
Tell the compiler to recognized C++ header(Well, that might not be
possible)
EDIT
#ifdef __cplusplus
# include MyCPPHeader.h
#endif
If I use that, would MyCPPHeader.h really get included in an Objective-C environment? I guess not. And that's against the principles of not hacking libraries.
EDIT
Even I changed these .mm files to include that C++ Header, i would get an link error saying Undefined symbols for architecture armv7:. This happens when my .mm files including .h headers in other libraries.
I have solved this a year ago, but for other people who are looking for an answer, here is the solution.
Say the C++ style header is named cpp.h. In my project, I never #import "cpp.h". I wrote a C style header, named c.h, as a wrapper header for cpp.h. Then I wrote a C++ implementation source file, named c.mm to implement the function define in c.h by calling functions in cpp.h. If I want to call functions in cpp.h, I #import c.h and use the wrapper function instead.
Below is the explanation in a possibly clearer way:
cpp.h C++ style header file using the namespace, its implementation is in assembly code so it is hard to change
c.h C style header as the wrapper for cpp.h
c.mm C++ implementation implements functions in c.h by calling functions in cpp.h
#import "c.h" to use the wrapper functions
I want to refer some stable library code which is not maintained by me. Actually it is some MFC code snippet.
But, whenever I want to include the code snippet, I have to #include entire file, which consequently I have to include other stuff, then the whole MFC ... The consequence is not acceptable.
Currently, I copy/paste the code snippet into my project, but I feel disgraceful. Can I just refer part of a file by C++ preprocessor?
Even the code is hard-linked with specific MFC version, it is better than duplicate them in my project. With such hard-link, I will know it's from MFC and save my time to check them.
Is there some super #include usage?
Can we write something like
#include "foo.h" line [12, 55)
which means to include line 22 to 54 for foo.h
What some have done is write #ifdef-sections in their headers to allow including files to only get specific parts. I don't know if your MFC file has those but you can look through it and use any existing ones or write your own.
The header usually look something like this
#ifdef USE_FANCYPANTS
bool hasFancyPants();
#endif
#ifdef USE_COOLSTUFF
void doCoolStuff();
#endif
And your include files then use #define before including.
#define USE_FANCYPANTS
#include "header.hpp"
Then you only get hasFancyPants() and not doCoolStuff()
You can use conditional compilation to inlcude/exclude stuff you dont need. You have to change the source code slighty, and amend project settings.
Can use typedef keyword, which would define types differently for MFC and non-MFC, and/or specific to your project settings, and the legacy code.
You may put entire stuff in a DLL or a .LIB (having code, not just declaration), and put the linker pragma in header file itself.
I am quite abeginner with all that C/C++ coding. Thay say that having C library with all headers turned into C++ in a fashon like:
#ifdef __cplusplus
extern "C" {
#endif
//.. header code
#ifdef __cplusplus
}
#endif
Will make it possibe to esely use practicly any C lib from sources (modified in such way). So I thought I shall give it at least a try. but I found I have like more than 300 headers... Ofcourse I will not use all of them but any way I'd prefere to make job once. So haw can I add such code to all headers? (I work with Windows, VisualStudio 2010 and 2008)
You only really need to do that if you have prebuilt C library code you are trying to interface your C++ code to.
If you still have the sources and are going to build all that C code yourself, you may find it easier to just submit them to the compiler as C++ code. With some compilers it is as simple as renaming the source files to *.cpp.
If that isn't workable, what I'd do is start with what you have, and only bother to put the extern "C" stuff around routines you need to use directly from your C++ code as you find them. That will surely be much less than the full 300 files, right?