Objective-C++ compilation errors due to Xcode not respecting file type - xcode

I'm following a tutorial in a book (iPhone 3D Programming), which uses:
Objective-C header and source files (file extensions .h, .m - respectively),
Objective-C++ header and source files (file extensions .h, .mm - respectively)
C++ header and source files (file extensions .hpp, .mpp - respectively)
A sample Xcode project is included which compiles successfully.
Before I found the sample project, I had manually typed out the code from the book but I was getting the following compilation errors for the files detailed below:
Unknown type name 'virtual'
Expected member name or ';' after declaration specifiers
IRenderingEngine.hpp (Xcode File Inspector - File Type = "Default - C++ Header")
...
struct IRenderingEngine {
virtual void Initialize(int width, int height) = 0; //2 errors as marked above
virtual void Render() const = 0; //2 errors as marked above
virtual void UpdateAnimation(float timeStep) = 0; //2 errors as marked above
virtual void OnRotate(DeviceOrientation newOrientation) = 0; //2 errors as marked above
virtual ~IRenderingEngine() {} //2 errors as marked above
};
...
Must use 'struct' tag to refer to type 'IRenderingEngine'
GLView.h (Xcode File Inspector - File Type = "Default - C Header")
#import "IRenderingEngine.hpp"
#import <QuartzCore/QuartzCore.h>
#interface GLView : UIView {
#private
EAGLContext* m_context;
IRenderingEngine* m_renderingEngine; //1 error marked above
float m_timestamp;
}
- (void) drawView:(CADisplayLink*)displayLink;
- (void) didRotate:(NSNotification*)notification;
#end
The file types for all the other files also defaulted to their expected file types in the Xcode File Inspector and as such should have worked correctly with the Build Setting - Apple LLVM compiler 4.2 - Language - "Compile Sources As = According to File Type" - which is identical to the Build Setting in the sample project that compiles successfully.
For some odd reason changing the Build Setting to "Compile Sources As = Objective-C++" in my manually created project removed the compilation errors and the application ran as expected.
Can anyone offer a reason as to why this setting is not consistent between seemingly identical (source-code-wise) projects?

Header files are not compiled. Header files are used by the preprocessor — anywhere you have a #include or a #import the actual text of the original is treated as though you'd copied and pasted it into the original.
Hence it doesn't matter if your file is called .hpp, .h or anything else. If a .m file imports a .h file that includes a .hpp file then the .hpp code will be compiled as part of the .m file, i.e. as Objective-C.
I am therefore going to guess that you've got GLView.m. If that's going to import a .hpp file, whether directly or indirectly, it needs to be compiled as Objective-C++. One way to do it is to rename it .mm, the other is to tell the project not to try to guess language types by file extension.

Tommy and HotLicks gave you the right answer to your immediate problem -- you need to make sure that all source files that include GLView.h are Objective-C files, by naming them .mm.
However, I want to add another side to this. Blindly making all files Objective-C++ is a bad solution. It should lead you to ask yourself: why do all these files need to be Objective-C++, if they are not using C++ features? The answer is that they import GLView.h, and the GLView class contains an instance variable whose type is a pointer to a struct that contains C++ features. Why do these other files care about that? They shouldn't.
There are various things you can do about it.
IRenderingEngine can be forward-declared in GLView.h. It is unnecessary to import IRenderingEngine.hpp, since the header doesn't care about the internal structure of IRenderingEngine; it only needs to know that it's some type in order to have a pointer to it. A forward declaration suffices for this. (However it would be necessary to write struct IRenderingEngine* m_renderingEngine; to be compatible with C.)
Furthermore, the instance variables for the GLView class do not need to be declared in the header in the first place. Instance variables can instead be declared in the implementation (.m) file either in the "class extension" (i.e. #interface GLView () { ... }), or, in newer versions of Xcode, directly in the class implementation (#implementation GLView { ... })

Related

ESP32 compiler giving "multiple definition of" errors

Got a new issue I've not come across before that's appeared when using the Espressif ESP32 ESP-IDF standard setup under VSCode. It uses the GNU compiler.
I'm getting "multiple definition of" errors on variables that share the same name, but which should be local.
So I use a .c and .h pair of files approach.
In my .c files I do this at the top
#define IO_EXPANDER_C //<<<This is a unique define for this file pair
#include "io-pca9539.h"
In my .h files I do this:
#ifdef IO_EXPANDER_C
//----- INTERNAL ONLY MEMORY DEFINITIONS -----
uint8_t *NextReadDataPointer;
//----- INTERNAL & EXTERNAL MEMORY DEFINITIONS -----
//(Also defined below as extern)
int SomeVariableIWantAvailableGlobally;
#else
//----- EXTERNAL MEMORY DEFINITIONS -----
extern int SomeVariableIWantAvailableGlobally;
#endif
It's a great simple system, any other .c file that includes the .h file (without the #define above its include statemnt), gets all of its extern variables, none of its local variables.
But, compiling in VSCode with my ESP-IDF based project, I'm getting "multiple definition of" errors relating to "NextReadDataPointer"
I use the same variable name NextReadDataPointer in another file pair in just the same way, but it's never declared anywhere as extern and each file pair uses a separate #define (IO_EXPANDER_C and LED_C). I do this all the time normally and I can't see any obvious mistakes.
I've never seen a C compiler do this before, it's as if it's mixing up the local definitions somehow. A #define should only have scope in the file it is declared in and in any includes within that file.
Even odder, the error is not generated if the project is built but a function is called from just one of the file pairs that share the same local variable name. It's only generated when functions are called from both file pairs from my main application.
Can anyone shed light on whether the GNU C compiler does something funky for a standard ESP-IDF project as it's got me baffled?
uint8_t *NextReadDataPointer; creates a variable which is visible across all translation units, i.e. it's the opposite of "private". If you include this header in multiple c files and the linker tries to link those together; it'll see a conflict. The keyword you're looking for is static, for example static uint8_t *NextReadDataPointer; creates a variable that is not visible across translation units. The reason you don't see the problem if calling a function from only one of those two files is because in this case the linker doesn't bother looking into the other one.
Personally I'd avoid such clever preprocessor hacks because it's quite difficult to see how files include one another and debug the resulting problems. I'd suggest sticking to the standard way of declaring shared things in header files and keeping the private stuff inside the c file (prepended by static).

Qt Creator : Intellisense for C, force a given context

So I have Qt Creator 7.0.2. The editor parses and colors and does lots of things with a given file, using the environment and the other files included.
However for header files, it does not take into account that this file is included in some compilation unit which provides some preexisting context (macros or types declared, other files already included, etc.) . Of course, one of the reasons for that is that there are multiple possibilities, but I do not know if Qt Creator offers a way to choose a context for parsing that would match one of those possibilities. Let me give an example with macros.
The file I am viewing in the editor : header.h
#ifdef A
/* Declarations in case of A */
#endif
#ifdef B
/* Definitions in case of B */
#endif
When viewing header.h in the editor, both paragraphs (in case of A, in case of B) are grayed out because in the context of header.h alone Qt Creator / Intellisense does not see a definition of A or B - and fair enough !
A compilation unit that includes this file : compilation_unit_A.c
#define A
#include "header.h"
/* Code using the definitions from the header file in case of A */
Another compilation unit that includes this file : compilation_unit_B.c
#define B
#include "header.h"
/* Code using the definitions from the header file in case of B */
I would like Qt Creator to offer me two options for parsing : in the context of compilation_unit_A.c or in the context of compilation_unit_B.c.
Then one or the other paragraph would not be grayed out and instead parsed like normal code, because one or the other of A and B would be defined.
In my case, definitions for A and B are themselves found in other header files included in each compilation unit, but if Qt Creator / Intellisense starts looking into the preexisting code in compilation_unit_A/B.c then it would also naturally open other header files to construct a context - like it already does.
EDIT : alternatively, I have one header file that, if "pretend-included" as part of the context, would cover almost everything. Can I ask Qt Creator to include all the contents of a given header file in its parsing for the editor ?

Importing header with C functions into Xcode proj?

I have a .h file with a single C style function:
void myFunc(NSArray *array) {
...
}
I want this function to be available in every file, so I #import "Functions.h" into my App-Prefix.pch file.
However, this gives me a compilation error ld: 38 duplicate symbols for architecture i386. What's the proper way to do this?
You should not implement the actual C function body in a header file, just like you shouldn't implement Objective-C methods in header files.
myfunc.h
void myFunc(NSArray *array);
myfunc.m
void myFunc(NSArray *array) {
...
}
Obviously, you should also add a #ifndef at the top of your header and if you decide not to use any Objective-C in myfunc.m, you can just as well rename it to myfunc.c.
Update:
The reason for this is that header files are collected from within multiple entry points in your program (multiple files). Then your compiler gets a little dizzy and starts wondering what function body you actually want to call (since there are multiple). A more obvious example would be declaring the same function name twice in a single C file. At the end, you should use header files to "describe" your function (add documentation and all that) and then use your main (.m) or C file (.c) to instruct the compiler what to do when that function gets called.

Can’t setBounds even with NS_BUILD_32_LIKE_64 macro

My project compiles and runs OK in debug mode, but when I switch to release x86_64 compiling, I get compiler errors for attempts to setBounds using NSRect. (The errors read “incompatible type for argument 1 of setBounds”.)
There are lots of posts which I take to be suggesting to add the NS_BUILD_32_LIKE_64 macro definition above the Cocoa (Foundation) import, so that the “if NS_BUILD_32_LIKE_64” language in NSGeometry.h will be true and the necesseary typedefs will be used. So I added the macro definition to the h file of the offending class:
#define NS_BUILD_32_LIKE_64 1
#import <Cocoa/Cocoa.h>
And I still get the same compile errors.
I also tried converting explicitly from NSRect to CGRect, so that instead of this . . .
// rectIncomingSource is an NSRect
calayer.bounds = rectIncomingSource;
. . . I wrote this:
calayer.bounds = CGRectMake(rectIncomingSource.origin.x, rectIncomingSource.origin.y, rectIncomingSource.size.width, rectIncomingSource.size.height);
Same errors.
And why would setting bounds be the only problem? Per Apple docs, NSInteger and NSUInteger are the main conversion problem, and I use them all over the place, but the compiler doesn’t complain about them. So why would it choke on bounds?
I’m probably missing something really simple here — for which I apologize to the wizards. Any help for the blind?
The target info window gave me the clue to figure this out:
I was putting the NS_BUILD_32_LIKE_64 define in a particular class's h file. It should have been in the prefix header file, the one with the pch extension that usually resides in the project's "Other Sources."
#ifdef __OBJC__
#define NS_BUILD_32_LIKE_64 1 // this line added
#import <Cocoa/Cocoa.h>
#endif
Well, yeah, I suppose this was obvious. But maybe some other preprocessor neophyte will find this clarification helpful, so I won't delete the question.
And I still don't understand why setting bounds should have been the only problem. Maybe something to do with core animation?

XCode: "Analyzer skipped this file due to parse errors"

my project includes a simple C file with a header. Like this:
#ifndef __IMAGE_ARRAY_3D
#define __IMAGE_ARRAY_3D
typedef struct ImageArray3D {
double *data; // The image data
LargeElement *largestElements; // c * nLargestElements
int c, w, h, nLargestElements;
} tImageArray3D; // Error points to here
...
#endif
When I run XCode's static analyzer, I get the following error:
Analyzer skipped this file due to parse errors
redefinition of 'ImageArray3D' as different kind of symbol
What is the cause of this?
Here is a solution for the problem: Solution!
The recommended solution is to add the
following to Other C Flags in your
project's build settings:
-D__IPHONE_OS_VERSION_MIN_REQUIRED=040100 where you replace 040100 with your
deployment target version (030000 for
3.0, for example).
Sounds like your project, or the OS X libraries, already define and use ImageArray3D. Just rename it and it will probably work.
I found the cause of it:
If you select XCode's Show issues only, then you won't see the analyzer's errors in a file! Only if you select Show all option, you will see that the analyzer has had problems checking your project.

Resources