Xcode: Integrate translated project by j2objc as "framework-target"

102 views
Skip to first unread message

Justin Ganzer

unread,
Aug 31, 2020, 5:37:16 AM8/31/20
to j2objc-discuss
Hello all!

I've translated a rather large java project of mine into Obj-c with the help of J2ObjC. Since changes to the project itself are infrequent, I've build a Make build chain which will result in a folder for the translated project.

Afterwards I included the translated files into my Swift project and added the necessary header files to my bridging header. Everything works splendidly!

Because of the size of the translated project, wanted to add a separate target which build and exports a framework which I can then integrate into my swift project. For a smaller translated library this works great, once making sure to supplement j2objc in the form of the provided xcframework.

Now the issue comes with my larger framework and its many dependencies that require to be build with many package directories due to many files having the same names, especially in my dependencies.

In the target (framework), i've included all header files which I had previously imported in my bridging header of my swift project and made them public in the "build phases" tab of xcode. The framework target itself builds just fine, but trouble arises when my swift project wants to build the "module" created by the framework.
It will find the header files that are made public but since they usually import further header files specified by a path such as "com/jts/SomeHeader.h", they're not found by my swift project anymore.
Now I could make the many dependent files public as well, but xcode will dump them all into a single header folder for the exported module, thus some files will clash with others that share the same name.

Does anyone have any solution to my problem?

What I already investigated:

1) Defining seperate module maps => Didn't really work out
2) Defining prefixes for packages and removing package directories with the use of J2ObjC flags. Sadly the functionality to include those prefixes into the filename as well has been put on hold a few years ago. Any updates perhaps?
3) Renaming my Java files isn't really an option I think, largely due to the fact most redundancies are inside dependencies.

Tom Ball

unread,
Aug 31, 2020, 1:14:47 PM8/31/20
to j2objc-discuss
One option you haven't tried is selectively using @ObjectiveCName to rename those Java classes that share names. If you don't want to or can't modify their source files, it's possible now to define annotations outside of the affected sources using a Java Annotation Index File (*.jaif), which j2objc supports with an -external-annotation-file flag. We use it to disable test methods by renaming them, but renaming classes is just as easy. For example, to rename java.sql.Date (since there's a java.util.Date) to SQLDate:

package java.sql:
  class Date:
    @ObjectiveCName("SQLDate")


--
You received this message because you are subscribed to the Google Groups "j2objc-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to j2objc-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/j2objc-discuss/a9f2be96-e84e-4e6d-ae14-b52dc9050899n%40googlegroups.com.

Justin Ganzer

unread,
Sep 2, 2020, 8:13:35 AM9/2/20
to j2objc-discuss
Hi Tom, thanks for the reply!

The "@ObjectiveCName" feature is very neat and I've used it quite a bit inside my project. However,
the issue isn't that there are class names colliding once imported, but rather that the file names collide when marking all necessary headers as public => Xcode drops all headers of the framework (that are marked "public") into a single "Header" folder, regardless of the folder structure they originated from, and uses that to automatically generate it's module.map. My guess is that maybe I shouldn't insist on using a framework inside the same xcworkspace and relying on XCode to correctly create a framework but instead build it manually, as there seems to be nothing I can do other than to mark said header files "public/private/project".

Having come to this conclusion, the issue of mine is not really related solely to J2ObjC, as it could happen with any two frameworks where files share the same name but differ in path.

But if it's not too much to ask, perhaps you (or anyone reading this) could share their experience in creating frameworks, xcframeworks or even static libraries from code created with J2ObjC? I'm guessing it all boils down to ensuring all the needed headers are available and their folder structure stays intact. Personally I've not had too much experience with frameworks and don't know what parts of it are essential to manually provide the accurate header files. Is it enough to define a script which manually pastes all needed headers into the "Headers" directory of the framework and add the Framework/Header path to the "User Header Search Paths" configuration of the project? Or will I run into trouble with this approach?


What I've done so far:
I've played around with it for some time, but usually ended in a dead end with each approach. Examples: Received warnings of "inclusion of non-modular header" (which makes sense because I just provided the headers besides the actual framework), or Xcode not wanting to build the project at all when I just manually injected the headers and their folder structure into the ".framework" after its been build. Here it actually just marked errors all over the place insisting that UIKit was not available for the iOS platform. And don't get me started with xcframeworks. Something I've come to love with Android is its documentation which in this case of Apple's xcframework is rather lackluster.
Message has been deleted

Tom Ball

unread,
Sep 2, 2020, 10:56:58 AM9/2/20
to j2objc-discuss
FWIW, we avoid using Xcode directly for builds since it has never been great about supporting headers with relative paths (at least, I haven't been able to get it to work). You can find the shell commands we use to create the J2ObjC distribution's frameworks in make/framework.mk

One trick we do is only include public headers in the framework and use that list to generate its "master" header file. It requires keeping a separate list of which sources define public classes, but that doesn't change often. Our build then verifies that the master header can be built by itself using different flag sets here.

If you're new to Make, the important bits are:
  • A build target is a label and colon, optionally followed by a list of dependencies that are built before the target is built.
  • The lines below a target are shell commands, each starting with a TAB character.
If you want to use Xcode, each Make build target can be converted to an External Build Tool target by copying the Make target's shell commands to the Xcode target's Arguments panel (in its Info panel), converting each line ending to a semi-colon.

There, that exhausts my very limited knowledge regarding XCFramework. Any further questions need to be asked where I ask them, on StackOverflow.com. :-)

On Wed, Sep 2, 2020 at 5:13 AM Justin Ganzer <fleisc...@gmail.com> wrote:
Hi Tom, thanks for the reply!

The "@ObjectiveCName" feature is very neat and I've used it quite a bit inside my project. However,
the issue isn't that there are class names colliding once imported, but rather that the file names collide when marking all necessary headers as public => Xcode drops all headers of the framework (that are marked "public") into a single "Header" folder, regardless of the folder structure they originated from, and uses that to automatically generate it's module.map. My guess is that maybe I shouldn't insist on using a framework inside the same xcworkspace and relying on XCode to correctly create a framework but instead build it manually, as there seems to be nothing I can do other than to mark said header files "public/private/project".

Having come to this conclusion, the issue of mine is not really related solely to J2ObjC, as it could happen with any two frameworks where files share the same name but differ in path.

But if it's not too much to ask, perhaps you (or anyone reading this) could share their experience in creating frameworks, xcframeworks or even static libraries from code created with J2ObjC? I'm guessing it all boils down to ensuring all the needed headers are available and their folder structure stays intact. Personally I've not had too much experience with frameworks and don't know what parts of it are essential to manually provide the accurate header files. Is it enough to define a script which manually pastes all needed headers into the "Headers" directory of the framework and add the Framework/Header path to the "User Header Search Paths" configuration of the project? Or will I run into trouble with this approach?


What I've done so far:
I've played around with it for some time, but usually ended in a dead end with each approach. Examples: Received warnings of "inclusion of non-modular header" (which makes sense because I just provided the headers besides the actual framework), or Xcode not wanting to build the project at all when I just manually injected the headers and their folder structure into the ".framework" after its been build. Here it actually just marked errors all over the place insisting that UIKit was not available for the iOS platform. And don't get me started with xcframeworks. Something I've come to love with Android is its documentation which in this case of Apple's xcframework is rather lackluster.

On Monday, August 31, 2020 at 7:14:47 PM UTC+2 Tom Ball wrote:
Reply all
Reply to author
Forward
0 new messages