Swift include icu4c

I use the icu4c as a systemLibrary in swift. There is some difficult during building.
I use the recently release of icu4c 67.1, and build install it successfully.
But when I include it in the SPM, building errors occur.

icu4c as below:
image

my project as below:




It seems that there is still exsiting some issues in the Xcode building swift?
When I just use the command line swift build, it successed.
And I use the swift package generate-xcodeproj generate the .xcodeproj file, open it with Xcode, every thing turns normal. wow

Or some default building config is inconsistent ?

But on the Ubuntu(docker), error occur again!

root@5b936ed50518:~/tmp/ImageMagickSwiftFoo# swift build
'ImageMagick' MagickWand.pc: warning: non whitelisted flag(s): -fopenmp, -DMAGICKCORE_HDRI_ENABLE=1, -DMAGICKCORE_QUANTUM_DEPTH=16, -fopenmp, -DMAGICKCORE_HDRI_ENABLE=1, -DMAGICKCORE_QUANTUM_DEPTH=16
/usr/bin/ld.gold: error: cannot find -licu-uc
clang-7: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
[0/1] Linking ImageMagickSwiftFoo

the linux :



image

@allevato
dear master, recently I explore using swift process emoji characters. You know the swift core doesn't support the UnicodeScalar.properties.isEmoji on platforms except MacOSX. So I search solutions on the github, and see your icu-swift, but when I dependent it, the swift build failed:
error: because icu-swift >=0.2.0 depends on icu4c-swift 1.0.1..<2.0.0 and every version of icu4c-swift contains incompatible tools version, icu-swift >=0.2.0 is forbidden. And because root depends on icu-swift 0.2.0..<1.0.0, version solving failed.

Now I have install ICU mannully from the latest source. On the MacOSX successfully, although there are many problems. But when I do the same thing on the Ubuntu(18), error occurs.

Do you have some suggestions?

@allevato
And what is "libicu-dev"?
After I apt-get install libicu-dev, and modifiey the module.modulemap file's link to "icuuc", swift build and swift run ImageMagickSwiftFoo successfully.

There are many different configurations between develop environment(MacOSX) and production environment(Linux), how to find a comfortable development way?

image

Finally I think the problem is the ld(linker) config does not been configured rightly.

  1. the library name
    Althought the pkgconfig tell you it's name is icu-uc, but on linux, the library file is named libicuuc.so, I have to set link in module.modulemap to icuuc( which on MacOSX icu-uc or icucore is ok, but icuuc is not ok).

  2. ld(linker) configurations doesn't been initialized.
    the ld's configurations is located in the /etc/ld.so.conf, or can be set use the environment variable
    LD_LIBRARY_PATH. All my icu library been installed at /usr/local/lib. And if I don't config the environment variable LD_LIBRARY_PATH, or neither run ldconfig, I can build successfully, but when I run swift run ImageMagickSwiftFoo, it will return error message error while loading shared libraries: libicuuc.so.67: cannot open shared object file: No such file or directory. The ld don't know where to find the library. So I had to set the environment variable LD_LIBRARY_PATH, or run ldconfig.

As a newbie, have set the pkgConfig in the Package.swift's systemLibrary, set the link in the module.modulemap, so at the beginning I think the swift will know everything, where to find the library( because all the things in the pkgconfig file(icu-uc.pc)), what's the library's name, it should know. But obviously I am wrong.

Everything about the development environment, about the production environment, is difficult for a newbie. :weary: :weary:

I don't know why I want to spend so long time to solve these confused problems. Not give up.

The first description maybe is wrong. I guess link should be icuuc both on Linux and MacOSX.

Thanks for the persistence to make icu4c, could you explain what's the benefit to switch to icu4c and the default icu library in Swift?

1 Like

If it succeeds with swift build and with the generated Xcode project, but fails when Xcode builds the package directly, it does indeed sound as if there is problem with how Xcode is building the package. It sounds as if different flags are being passed to the linker, as you have discovered. Would you mind opening a bug report against Xcode (using Bug Reporting - Apple Developer) and referencing the package and which SHA1 of it is causing the problem? Xcode should be able build packages the same way as SwiftPM does on macOS, and this should certainly be a smoother experience than it has been for you. Thanks!

1 Like

Hmm, that doesn't seem rightโ€”it should be supported on any platform that's using ICU 57 or higher. That would include macOS 10.12, iOS 10, tvOS 10, watchOS 3, and I think that should also include Ubuntu 18.04 and later (or maybe even 16.10).

To be honest I abandoned my attempts to wrap Swift bindings around built-from-source icu4c because of how much of a pain it was to build everything consistently and correctly across all platforms. Another issue was the way icu4c APIs are versioned (using preprocessor macros to add version number suffixes to the function names) made it challenging to write Swift code that knew which versions of the functions it could call without having to manage a bunch of handwritten C shims.

Ironically, it was much easier to just add APIs to the standard library than to get a third-party solution working.

So unfortunately, I don't have much advice to offer in this area.

:sweat_smile: :sweat_smile: :sweat_smile:
Is there a icu library in Swift? I don't know it.

Ok, I will report it soon.

yep, this is the warning on Ubuntu18:

  3> a.unicodeScalars.first?.properties.isEmoji
error: repl.swift:3:36: error: value of type 'Unicode.Scalar.Properties' has no member 'isEmoji'
a.unicodeScalars.first?.properties.isEmoji
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~


  3> :q
root@821a20f4b81e:/# swift --version
Swift version 5.2.5 (swift-5.2.5-RELEASE)
Target: x86_64-unknown-linux-gnu

And this is the code defined isEmoji I find in the Xcode

   /// A Boolean value indicating whether the scalar has an emoji
   /// presentation, whether or not it is the default.
   ///
   /// This property is true for scalars that are rendered as emoji by default
   /// and also for scalars that have a non-default emoji rendering when followed
   /// by U+FE0F VARIATION SELECTOR-16. This includes some scalars that are not
   /// typically considered to be emoji:
   ///
   ///     let scalars: [Unicode.Scalar] = ["๐Ÿ˜Ž", "$", "0"]
   ///     for s in scalars {
   ///         print(s, "-->", s.isEmoji)
   ///     }
   ///     // ๐Ÿ˜Ž --> true
   ///     // $ --> false
   ///     // 0 --> true
   ///
   /// The final result is true because the ASCII digits have non-default emoji
   /// presentations; some platforms render these with an alternate appearance.
   ///
   /// Because of this behavior, testing `isEmoji` alone on a single scalar is
   /// insufficient to determine if a unit of text is rendered as an emoji; a
   /// correct test requires inspecting multiple scalars in a `Character`. In
   /// addition to checking whether the base scalar has `isEmoji == true`, you
   /// must also check its default presentation (see `isEmojiPresentation`) and
   /// determine whether it is followed by a variation selector that would modify
   /// the presentation.
   ///
   /// This property corresponds to the "Emoji" property in the
   /// [Unicode Standard](http://www.unicode.org/versions/latest/).
   @available(OSX 10.12.2, iOS 10.2, tvOS 10.1, watchOS 3.1.1, *)
   public var isEmoji: Bool { get }

Unfortunately, the error doesn't appear ever again. :weary: