Liferay Silicon Mac Theme Development Issues

You'll hit a common JSASS issue trying to build themes on Macs with the Silicon chips. Building on a solution from Julien Bédia, it ends up being easy to work around...

Solving Silicon Issues

My good friend Andrew Jardine has started upgrading his Mastering Liferay site, currently on 7.1, and he's going to be upgrading it to the latest 7.4.

However, he recently was blessed with a new M3 MacBook and, when he was trying to build his 7.1 workspace, he was hit with an error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: 
    /private/var/folders/96/cz9djc7j5bq3hgm97kxrv1wh0000gn/T/
      libjsass-8817744974539649035/libjsass.dylib: 
    dlopen(/private/var/folders/96/cz9djc7j5bq3hgm97kxrv1wh0000gn/T/
      libjsass-8817744974539649035/libjsass.dylib, 0x0001): 
    tried: '/private/var/folders/96/cz9djc7j5bq3hgm97kxrv1wh0000gn/T/
      libjsass-8817744974539649035/libjsass.dylib' (mach-o file, 
      but is an incompatible architecture (have 'x86_64', need 'arm64e' or 'arm64')),
      '/System/Volumes/Preboot/Cryptexes/OS/private/var/folders/96/
        cz9djc7j5bq3hgm97kxrv1wh0000gn/T/libjsass-8817744974539649035/libjsass.dylib' 
      (no such file), '/private/var/folders/96/cz9djc7j5bq3hgm97kxrv1wh0000gn/T/
        libjsass-8817744974539649035/libjsass.dylib' (mach-o file, 
      but is an incompatible architecture (have 'x86_64', need 'arm64e' or 'arm64'))
  at java.lang.ClassLoader$NativeLibrary.load(Native Method)
  at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1950)
  at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1832)
  at java.lang.Runtime.load0(Runtime.java:783)
  at java.lang.System.load(System.java:1100)
  at io.bit3.jsass.adapter.NativeLoader.loadLibrary(NativeLoader.java:49)
  at io.bit3.jsass.adapter.NativeAdapter.(NativeAdapter.java:28)
  at io.bit3.jsass.Compiler.(Compiler.java:32)
  at com.liferay.sass.compiler.jsass.internal.JSassCompiler.compileFile(
    JSassCompiler.java:113)
  at com.liferay.css.builder.CSSBuilder._parseSass(CSSBuilder.java:395)
  at com.liferay.css.builder.CSSBuilder._parseSassFile(CSSBuilder.java:407)
  at com.liferay.css.builder.CSSBuilder.execute(CSSBuilder.java:166)
  at com.liferay.css.builder.CSSBuilder.main(CSSBuilder.java:80)

I had never heard of this error, but my other friend Fabian Bouché had a handy link from an article by Julien Bédia: Problème de build d'un Module Liferay Gradle et la librairie libjsass sur ARM.

Don't let the fact that the article is in French scare you off; Safari and Google both were able to translate it for me and was very easy to follow and apply.

In the article, Julien is solving a different problem, namely having SCSS files in the portlet module builds which also fails trying to run JSass, but his solution also works for solving the theme issue.

There was just one problem that Andrew had... When following the instructions, his theme project would build fine, but his java modules (that didn't have any SCSS/SASS files) would fail.

Julien's solution works, but each system needs to be updated with a global init routine that modifies all gradle modules with or without SCSS/SASS requirements.

Working with Andrew, we changed things up just a bit...

First, we tossed the global init piece as it was causing problems in general.

Next, we went to the build.gradle file for his theme, and we just added to it:

tasks.withType(JavaExec) {
  doFirst {
    def isMac = System.properties['os.name'].toLowerCase().contains('mac')
    def arch = System.properties['os.arch']
    def isAppleSilicon = arch == 'aarch64' || arch == 'arm64'

    if (isMac && isAppleSilicon) {
      def libsDir = 
        file("${System.properties['user.home']}/.gradle/libs").absolutePath
      environment 'DYLD_LIBRARY_PATH', libsDir
      jvmArgs = ["-Djava.library.path=${libsDir}"] + jvmArgs
    }
  }
}

One advantage of this approach is that you only add it to those modules that need SASS compilation.

Other modules that don't have this stanza won't have it in place and won't be affected by it.

For Julien's portlet modules, the same change should work, adding in the logic for libjsass in the build.gradle for the individual modules will fix the build issues there too.

Another advantage of this approach is it puts the change in the build.gradle where it can be committed to SCM, so the change is part of the project and not part of the environment.

The final advantage to this approach, it takes the environment into account when determining whether to apply the change or not. Since I'm testing if you're on a Mac and it is based on one of the Silicon chips, I don't have to worry when my CI/CD system is building the theme, it won't apply these changes. But if I am building locally on my M2 Mac Mini, Andrew is building on his M3 MacBook, or Julien is building on his system, everyone should be able to successfully build.

Of course the Silicon-based folks will have to follow Julien's setup to get the suitable libjsass set up and installed, but they'll only need to do that once. The workspace will pull it in when it needs it and ignore it when it doesn't.

Of course there's a glaring disadvantage of this approach - you have to manually copy and paste this stanza into those modules where the build fails. This duplication is not efficient and makes maintenance a pain. Given the advantages, including the no impact to non-Silicon systems and the team sharing aspects, though, I feel like the advantages outweigh the disadvantages.

Many, many thanks to Julien Bédia for sharing his solution with us, this blog was so easy to write since he truly did all of the hard work...