Missing uObjC from global namespace (iOS foreign code)

Hi,

Just try to compile my project with foreign code and encounter this error when compiling in XCode

Error: no member named 'uObjC' in the global namespace

After I check the code, it seems that it’s coming from fuse generated source code. I have to add #include "uObjC.String.h" manually in generated source code through XCode. This issue was not the case in previous build (last time I try to compile this code is with build 0.21), and currently I’m using latest build (0.27)

Same issue here

Hello, and thanks for your report.

Can either of you share your code? I just made a minimal app with some foreign code but didn’t run into this. What should happen (and it does for me) is that any generated code that uses foreign code should get the uObjC.Foreign.h include (which transitively includes uObjC.String.h), so perhaps you’re running into some problem with that mechanism.

Cheers!

Hi,

I was building this project
https://github.com/zean00/fuse-qreader and got that error.

And I think it’s caused by code generated by this function

Objective C code

- (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result
{
    @{QreaderImpl.Picked(string):Call(result)};
    [self.uivc dismissViewControllerAnimated:YES completion:nil];
}

UNO code

public static void Picked (string result) {
		InProgress = false;
		FutureResult.Resolve(result);
	}

Ah, it’s in an external Objective-C++ (.mm) source file, and not in an Uno file. To use UXL macros (the @{...} bit in your code) to call back to Uno from such a file you have to add the uObjC.Foreign.h include yourself, as mentioned in the docs.

Hi,

Yes, you are correct, sorry I didn’t notice that since this was not the case with previous build (0.20). The error is gone now. Thanks :slight_smile:

Hi and sorry for the late reply,

I added

#import "uObjC.Foreign.h"

at the beginning of the .mm file, but Xcode shows the same error (uObjC.h file not found).

I am using this example: https://github.com/bolav/fuse-camerapanel, imported in my main project as an external project.
In the external project’s .unoproj file there is:

"RootNamespace":"",
    "Packages": [
    "Fuse",
    "FuseJS",
    "Android",
    "Uno.Permissions"
  ],
  "Includes": [
    "./*.uno",
    "./*.uxl",
    "FuseCameraImpl.h:ObjCHeader:iOS",
    "FuseCameraImpl.mm:ObjCSource:iOS",
    "CameraAndroid.java:Java:Android"
  ]

Thanks for your support,

Hey!

That’s not the same error as above, though it looks similar, so the fix above might not work for you.

The file uObjC.h comes from a part of our automatically generated iOS library bindings (which are deprecated in favour of foreign code), but the project doesn’t actually reference the package that includes the file. From a quick glance it looks like the include might not actually be necessary and/or can be replaced with uObjC.Foreign.h. If it turns out it’s needed it should work after adding ObjC to the Packages list in the unoproj.

Hope that helps!

Hi Olle and thanks for the quick reply,

In the project, the .mm file is used by an .uxl as follows, where uObjC is tagged as required include:

<Extensions Backend="CPlusPlus" Condition="iOS">
	<CopyFile HeaderFile="FuseCameraImpl.h" />
	<ProcessFile SourceFile="FuseCameraImpl.mm" />
    <Type Name="CameraImpl">
    	<Set FileExtension="mm" />
    	<Require Entity="Uno.Action" />
       	<Require Entity="ObjC.Object" />
       	<Require Source.Import="FuseCameraImpl.h" />
       	<Require Source.Include="uObjC.h" />
       	<Method Signature="allocateCamera():ObjC.ID">
...

I first tried to remove the uObjC.h include line, but got the same error in Xcode (uObjC.h file not found).

Then, I reverted the delete and added ObjC to the .unoproj as follows, but the error is still there,

{
  "RootNamespace":"",
    "Packages": [
    "Fuse",
    "FuseJS",
    "Android",
    "Uno.Permissions",
    "ObjC"
  ],
  "Includes": [
    "./*.uno",
    "./*.uxl",
    "FuseCameraImpl.h:ObjCHeader:iOS",
    "FuseCameraImpl.mm:ObjCSource:iOS",
    "CameraAndroid.java:Java:Android"
  ]
}

Maybe I am adding it wrong?

Hey again!

Can you try uno clean before building again? I can’t see where else that file is included.

Hey, so I tried uno clean, uno build each time with the following changes:

  • adding “ObjC” to the .unoproj file
  • removing
<Require Source.Include="uObjC.h" />

from the .uxl file

  • replacing it by
<Require Source.Include="uObjC.Foreign.h" />

the initial error disappeared but I get:

in the .mm file in Xcode :confused:

Now you’re running into the problem of the original post, so try adding #include <uObjC.Foreign.h> to FuseCameraImpl.mm. :slight_smile:

Oh! I tried that, but the errors remain TT, having:

.unoproj:

{
  "RootNamespace":"",
    "Packages": [
    "Fuse",
    "FuseJS",
    "Android",
    "Uno.Permissions",
    "ObjC"
],
  "Includes": [
    "./*.uno",
    "./*.uxl",
    "FuseCameraImpl.h:ObjCHeader:iOS",
    "FuseCameraImpl.mm:ObjCSource:iOS",
    "CameraAndroid.java:Java:Android"
  ]
}

.mm:

#import <CoreVideo/CVOpenGLESTextureCache.h>
#import "FuseCameraImpl.h"
#include <uObjC.Foreign.h>
#import <OpenGLES/ES2/glext.h>
...

.uxl:

<Extensions Backend="CPlusPlus" Condition="iOS">
	<CopyFile HeaderFile="FuseCameraImpl.h" />
	<ProcessFile SourceFile="FuseCameraImpl.mm" />
    <Type Name="CameraImpl">
    	<Set FileExtension="mm" />
    	<Require Entity="Uno.Action" />
       	<Require Entity="ObjC.Object" />
       	<Require Source.Import="FuseCameraImpl.h" />        
       	<Require Source.Include="uObjC.h" /> Or/And <Require Source.Include="uObjC.Foreign.h" />

It looks like the error is in FuseCameraImpl.mm, so add the include there.

Sorry I was not clear, the .mm file code snippet in my previous response corresponds to FuseCameraImpl.mm

Ah, sorry, I misunderstood that part. Is the error exactly the same or something new? Remember to clean as well. :slight_smile:

Yes, with the configuration above the errors are:

Even getting parse errors, for instance, the last one saying the last } should be removed, when I don`t think it should:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection
{
    if (_textureHandle)
        CFRelease(_textureHandle);
        
     if (_videoTextureCache)
        CVOpenGLESTextureCacheFlush(_videoTextureCache, 0);
    
    uAutoReleasePool pool; // Do we need this???
	CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    _textureWidth = CVPixelBufferGetWidth(pixelBuffer);
    _textureHeight = CVPixelBufferGetHeight(pixelBuffer);
    
    if (!_videoTextureCache)
    {
        NSLog(@"No video texture cache");
        return;
    }

    glActiveTexture(GL_TEXTURE0);
    CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(
        kCFAllocatorDefault,
        _videoTextureCache,
        pixelBuffer,
        NULL,
        GL_TEXTURE_2D,
        GL_RGBA,
        (GLsizei)_textureWidth,
        (GLsizei)_textureHeight,
        GL_BGRA_EXT,
        GL_UNSIGNED_BYTE,
        0,
        &_textureHandle);

    // Check orientation of device
    // Check orientation of frame
    _textureOrientation = connection.videoOrientation;
    // NSLog(@"%d", connection.videoOrientation);

    // Rotate frame


    if (err)
    {
        NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
        //if (vs->ErrorHandler)
        //{
        //    @{Uno.Action:Of(vs->ErrorHandler):Call()};
        //}
    }

    glBindTexture(CVOpenGLESTextureGetTarget(_textureHandle), CVOpenGLESTextureGetName(_textureHandle));
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    // CVBufferRelease(pixelBuffer);
    // Set Texture of Camera
    int _th = CVOpenGLESTextureGetName(_textureHandle);
    [self setTexture:_th];
    // Call callbackhandler
    if(_callback != NULL)
    {
        @{Uno.Action:Of(_callback):Call()};
    }
}

Looks like there’s a macro in a comment that goes a bit wild when it’s expanded.

Try removing the following:

        //if (vs->ErrorHandler)
        //{
        //    @{Uno.Action:Of(vs->ErrorHandler):Call()};
        //}

Ok, I removed all the commented code blocks in the .mm file.
There are only 2 errors now:

It looks like those files are not written with Foreign Objective-C in mind since you’re getting type errors, so you might have a better time if you set filetype to CSource and CHeader instead of ObjCSource and ObjCHeader in the unoproj. UXL macros are expanded in a way that’s compatible with foreign code if you use ObjCSource/Header, doing some boxing and unboxing of objects automatically. But it looks like this code is written assuming the macro expansion is just the plain expansion that we do for C and C++.