How to make custom C code into a SwiftPM package? - ios

I am trying to package C code into a Swift module, let's call it CModule. Once I have put it into the base folder of a project (SwiftModule) and configured the Search Paths, I could get auto-complete to work in the Swift files, as well as detect errors/warnings.
The problem is, it won't recognize the module when it's imported, and Jump to Definition results in the following error:
Couldn't Generate Swift Representation
Error (from SourceKit):
"Could not load module: CModule"
CModule contains the following files:
src folder, containing the implementation and an umbrella header exposing all required functions (by importing other sub-headers) such
that main_header.h imports componentA.h, componentB.h etc
module.modulemap, containing only:
module CModule [system] {
header "src/main_header.h"
export *
}
The CModule folder is then put at the root of the SwiftModule project.
The framework and import search paths are defined as follows: $(PROJECT_DIR)/CModule (recursive)
Considering auto-complete and others work, I am confident the import search path is set correctly. No idea about the framework search path.
Additional details:
There are no spaces anywhere in my paths.
SwiftModule is a "framework" that will eventually be put on CocoaPods.
There are no public headers but the base SwiftModule header. CModule headers are all defined as Project headers.

Related

Wrapping an existing C library as a Framework

I am trying to find a way of wrapping an existing C library with an Apple .framework structure. The key sticking point is avoiding the need to specify the Search Headers field in Settings.
Typically in a framework you specify something like:
#import <Foundation/Foundation.h>
where Foundation is the framework name and the .h file is an umbrella header.
When testing with existing code, for the sake of argument OpenSSL, the project is using #include <openssl/file.h> internally to refer to its files. Once you want to place this inside a framework for convenience every include naturally needs to be changed to <NameOfFramwork/openssl/file.h> or you must add the $(SRCROOT)/Path/To/Frameworks/NameOfFramework.framework/Headers to the search path. This is terribly inconvenient and kills a lot of the value of the framework format. It only becomes worse when you want to wrap multiple SDK versions of the library in an XCFramework.
I'm wondering specifically if the ModuleMap can help avoid the need to change the #includes? I've added a modulemap I'm creating as a test.
Experimental module.modulemap
framework module LibreSSL [extern_c] {
umbrella header "LibreSSL.h"
export *
module * { export * }
explicit module LibreSSL_Private [extern_c] {
umbrella "Headers/include"
link "LibreSSL"
export *
}
}
One unsatisfying solution is to switch to an XCFramework comprised of Libraries instead of Frameworks.
xcodebuild \
-create-xcframework \
-library <path/to/library> \
-header <path/to/headers> \
-output MyCool.xcframework
Then header search paths work correctly, but you lose the .modulemap and the nice framework structure that keeps everything together neatly per SDK build.

Static library and header chaining issues

I have three projects in XCode.
ProjectA, a pure C project
ProjectB, a objective C project
ProjectC, a mix of objective C and Swift
ProjectA is a static library project used in ProjectB.
Header files from projectA are in copy file target, it is in ProjectB\lib\ProjectA.a and \lib\include folder.
ProjectB is linked as a sub project in ProjectC.
ProjectC imports some header file from ProjectB.
Those header files in ProjetB have imported header files in ProjectA.
My problem is, ProjectA is not visible in ProjectC. ProjectC compilation fails since ProjectC imports headers from ProjectB and B has header files imported from projectA.
What is the way to solve this C->A dependency on .h files?
In ProjectA.
file DesTypes.h:
// some types are defined here.
In ProjectB.
ProjectA.a is linked as static lib.
File CryptoUtil.h :
#import DesTypes.h
// some function prototypes used types from Destypes. The .h is in search header path. So no problem.
I need the import here since some function prototype uses the types from DesTypes.h.
Otherwise importing DesTypes.h in CryptoUtil.m file would solve the problem.
In ProjectC
File MyViewController.h:
#import CryptoUtli.h
// Here I get compile error for chaining. I do not use anything from DesType.h.

bridging swift and objective-c

I have objective-c project and I added swift files in it. i created bridge file and imported swift file in some header files without problems.
But I need to import some header files to swift files by adding them in the "<project-name>-Bridging-Header.h" file.
If I put header file in that bridge file and this header file was import swift file before; Xcode give me error message: "file not found" for the swift bridge file.
i.e:
I have project name called: "ProjectBlaBla"
I have header file called "readingPage.h"
I have swift file called: "readingSwift.swift"
swift bridge file's name: "ProjectBlaBla-Swift.h"
I created header bridge file: "ProjectBlaBla-Bridging-Header.h"
I imported "ProjectBlaBla-Swift.h" in "readingPage.h" file without problem and used swift classes inside objective-c
when I import "readingPage.h" in the "ProjectBlaBla-Bridging-Header.h", I got error message in "readingPage.h" said: "ProjectBlaBla-Swift.h file not found"
any suggestions ?
thanks
You are not able to reference -Swift.h files directly or indirectly in -Bridging-Header.h files.
If you open -Swift.h, you will see a line near the top, in my case line 99: #import "/Users/.../...-Bridging-Header.h", meaning -Swift.h already imports -Bridging-Header.h, so importing back creates a circular dependency.
To avoid this, any header you import in -Bridging-Header.h must use forward references to Swift classes or protocols it uses as described in answers to this question.
In short, if readingPage.h uses a Swift class named MySwiftClass you should:
Remove any references to -Swift.h from readingPage.h.
Import -Swift.h in readingPage.m
Insert #class MySwiftClass; into readingPage.h before the class is used, letting Objective-C know that such a class exists and is declared elsewhere.
Check whether the bridging header path is correct. On the left, select your project name -> TARGETS -> Build Settings -> search for Objective-C Bridging Header. Refer the photo below.
Two options
Import the "ProjectBlaBla-Swift.h" inside the "readingPage.m" file instead of "readingPage.h" file
Create a new PCH file named "Prefix.pch" and import "ProjectBlaBla-Swift.h" inside the "Prefix.pch" file.
Note: Prefix.pch is a precompiled header which makes compiling faster. You do not need to reimport any files that are imported in prefix.ch file.

The included part ''xclickcounter.dart'' must have a part-of directive

Create a sample web application using the Web UI (web_ui) library, e.g., mylib
open mylib.dart, make it a library:
library mylib;
import 'dart:html';
import 'package:web_ui/web_ui.dart';
part 'xclickcounter.dart';
...
open xclickcounter.dart, remove imports and insert:
part of mylib;
web/out/mylib.dart and web/out/xclickcounter.dart get messed up:
The included part ''xclickcounter.dart'' must have a part-of directive
Classes can only mixin other classes
Mixin can only be applied to class
... more errors follow
What am I doing wrong? Please help :(
Edit: if I don't edit generated sample code, wdc will generate code that falls into separate libraries:
web/out/xclickcounter.dart => x_click_counter
web/out/mylib.dart => mylib_html
Does it mean that if we use web_ui we should not create our own libraries and wdc will do this for us automatically?
Update: if I don't use any library name, similar to what generated sample code does, and only rely on the library names generated by xdc in web/out/... files, I still run into trouble when importing my two components into a 3rd file. Dart Editor will produce the following warning:
The imported libraries 'compa.dart' and 'compb.dart'
should not have the same name
The workaround is to name your libraries based on what xdc produces in web/out/... files, that is:
compa.dart => x-comp-a
compb.dart => x-comp-b
After explicitly placing components into libraries like these the Dart Editor warning disappears.

dartEditor file hierarchy and library/part logic

When I create a 'Web Application' with DartEditor in Windows8, it gives me this hierarchy
ClientView/
packages/
pubspec.lock
pubspec.yaml
web/
packages/
clientview.css
clientview.dart
clientview.dart.js
clientview.dart.js.deps
clientview.dart.js.map
clientview.html
I then add the lib/ file:
web/
...
lib/
src/
canvas.dart
i_drawable.dart
node.dart
client_canvas.dart
...
client_canvas.dart file
library client_view;
import 'dart:html';
import 'package:meta/meta.dart';
// Interface
part 'src/i_drawable.dart';
// Class
part 'src/canvas.dart';
part 'src/node.dart';
In each of the files included after the 'part' keyword, I've added this line:
part of client_view;
But it seems that none of the classes can be accessed by the other dart code
class Canvas implements IDrawable // no such type 'IDrawable'
abstract class Node implements IDrawable // no such type 'IDrawable'
class CustomNode extends Node // no such type 'Node' (if try to create a custom node)
I guess it's the way pubs and library are organized that I've not understood yet.
So what I tried to do is to create a library, inside the same project, I'd like to import that library inside the clientview.dart file that is called by the clientview.html file.
Your help would be greatly appreciated!
Since you're using relative imports, and everything appears to be part of the same library, I see no obvious reason for the errors. Maybe you can share some more details.
You should probably reorganize your source tree to be more inline with Pub standards though. web/ and lib/ should both be top level directories, otherwise you won't be able to do package: imports of your own libraries. This is one reason why it's recommended that web/ only contain entry points (scripts with a main() method) and everything else should be in lib/.
Also, I would try to use part very sparingly. I find it much better to define almost every file as a library and just import them. It makes dependencies for each file much more clear and allows consumers to only import the interfaces, and not the implementations. export makes it possible to build a library that exposes the definitions of another.
Finally, a style nit: Dart isn't C# and we don't use that ugly 'I' prefix on our interfaces :-) Just name your interface Drawable.

Resources