Build / Compile latest SalaJS (1.3+) using gradle on a windows machine? - gradle

Does anyone know if this is possible? I have ran into the following solutions:
There is a shell script that can act as 'sbt' and can be invoked in gradle using an 'exec' task but it is limited to a linux OS. I would ideally like an OS independent solution.
There is a gradle plugin for scalajs but it is relatively old (and seems no longer maintained), supporting up to version 0.6, whereas scalajs is already on version 1.3+.
ScalaJs has a 'scalajs-compiler' jar, and I am wondering if this can be used to compile a scalajs project rather than relying on SBT, if there is any documentation covering this, a reference will be greatly appreciated. Thank you all for your help.

Scala.js CLI
The Scala.js CLI (GitHub / Download) should work with *NIX systems and windows. However, there is another problem: it doesn't automatically use new versions of Scala.js. So currently, it will only give you Scala.js 1.0.0 functionality. We have not yet figured out how to solve this problem.
Compiling Scala.js yourself
The Scala.js compiler is simply a Scala compiler plugin. You simply need to invoke the Scala compiler with additional arguments:
scalac \
-classpath $CLASSPATH:scalajs-library_2.13-1.4.0.jar \
-Xplugin:scalajs-compiler_2.13.4-1.4.0.jar \
$FILES
This will produce .class and .sjsir files for the provided .scala files.
The versions of scalajs-library / scalajs-compiler must match the version of Scala you are compiling. Further, note that the compiler version must match exactly, the library needs to match in the minor version.
scalajs-library on maven
scalajs-compiler on maven
example in the Scala.js CLI
Linking Scala.js yourself
Unlike Scala for the JVM, Scala.js requires a linking step. The Scala.js linker comes as a standalone library. (artifacts on maven, Interface API).
Both the Scala.js CLI and the sbt plugin use this library to link Scala.js code. However, the CLI is outdated and the sbt plugin complicated. So instead of linking to an example, I'll just provide one here:
import java.nio.file.Path
import org.scalajs.logging._
import org.scalajs.linker.StandardImpl
import org.scalajs.linker.interface._
import scala.concurrent.ExecutionContext.Implicits.global
def link(classpath: Seq[Path], outputDir: Path): Unit = {
val logger = new ScalaConsoleLogger(Level.Warn)
val linkerConfig = StandardConfig() // look at the API of this, lots of options.
val linker = StandardImpl.linker(linkerConfig)
// Same as scalaJSModuleInitializers in sbt, add if needed.
val moduleInitializers = Seq()
val cache = StandardImpl.irFileCache().newCache
val result = PathIRContainer
.fromClasspath(classpath)
.map(_._1)
.flatMap(cache.cached _)
.flatMap(linker.link(_, moduleInitializers, PathOutputDirectory(outputDir), logger))
Await.result(result, Duration.Inf)
}
This will link all the Scala.js code in classpath and put the resulting file(s) into outputDirectory.

Related

Gradle Idea plugin - issues with specifing test sources

I'm trying to create a custom source set and mark its contents in Intellij Idea as a Test Sources Root. I tried to use idea plugin and do it according to the gradle official website but it is not clear for me how it works.
First of all the documentation specifies the following configuration setup
idea {
module {
testSources.from(sourceSets["intTest"].java.srcDirs)
}
}
When I try to use it i receive Unresolved reference: testSources. Where is it coming from?
Then I tried to use:
idea {
module {
testSourceDirs = intTest.java.srcDirs
}
}
it works fine as long as I use only Java. After applying Kotlin plugin however, both kotlin and java + resources folder are again treated as Sources Root not Test Sources. To fix that I had to change from:
testSourceDirs = intTest.java.srcDirs
to:
testSourceDirs = intTest.kotlin.srcDirs
and now all folders are Test Source Root again. Since kotlin.srcDirs also includes java.srcDirs it looks like you have to specify all, otherwise it is ignored...
Now the real issue came when I used gradle-avro-plugin. Applying it made my folders marked as Sources Root again. I believe it is because it adds another avro directory, but just to main source set.
Does anyone know how to make it marked as Test Sources having both kotlin and avro plugin applied? Am I doing something wrong here? Beacause this beheviour seems to be buggy in the first place.
Tested with:
IntelliJ IDEA 2022.3.1 (Ultimate Edition)
Gradle 6.8.3 and 7.4.2
Plugin id("com.github.davidmc24.gradle.plugin.avro") version "1.5.0"
Plugin kotlin("jvm") version "1.7.0"

Use Groovy app and test code in combination with jlink solution for bundling JavaFX

This follows on from this excellent solution to the question of how to get Gradle to bundle up JavaFX with your distributions.
NB specs: Linux Mint 18.3, Java 11, JavaFX 13.
That stuff, involving jlink and a module-info.java, is beyond my pay grade (although I'm trying to read up on these things).
I want to move to using Groovy in my app and test code (i.e. Spock) rather than Java. The trouble is, the minute I include the "normal" dependency in my build.gradle i.e.
implementation 'org.codehaus.groovy:groovy-all:2.5.9'
and try to build, I get multiple errors:
mike#M17A ~/IdeaProjects/TestProj $ ./gradlew build
> Configure project :
Found module name 'javafx.jlink.example.main'
> Task :compileTestJava FAILED
error: the unnamed module reads package org.codehaus.groovy.tools.shell.util from both org.codehaus.groovy.groovysh and org.codehaus.groovy
[...]
error: the unnamed module reads package groovy.xml from both org.codehaus.groovy and org.codehaus.groovy.xml
[...]
error: module org.codehaus.groovy.ant reads package groovy.lang from both org.codehaus.groovy and org.codehaus.groovy.test
error: module org.codehaus.groovy.ant reads package groovy.util from both org.codehaus.groovy.xml and org.codehaus.groovy.ant
100 errors
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileTestJava'.
Yes, 100 errors... probably more! By commenting out various things I think I've come to the conclusion that some Groovy dependency is being injected by the jlink stuff. Fine, I can live with that (although it'd be nice to know what version of Groovy it is).
The trouble is, even if I omit the Groovy dependency line, the same errors occur when I try to introduce the Spock dependency:
testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
Has anyone got any idea what's going on here and what to do about it?
I searched for an answer. I didn't find a good solution.
According to this, it seems that Groovy is currently not really compatible with Java modules. It is due to the fact that some packages are contained by multiple jars of the library (not compatible with modules). You will have to wait for Groovy 4 for a compatible version.
I discovered that the JavaFX plugin use this plugin internally. This plugin seems to consider that all dependencies are modules (it is not the default Gradle behaviour).
To make your application works, it seems that you have to:
force Gradle to put Groovy in the classpath instead of the modulepath (it will not be considerered as a module, but seems impossible if you use the javafx plugin)
use the "patch-module" system: it allows Gradle to make a fusion of the library jars into a single module, to prevent the problem of packages that are in different jars
I searched the Groovy jars with IDEA (Project structure/Libraries), and I tried to use the syntax offered by the plugin to use "patch-module":
patchModules.config = [
"org.codehaus.groovy=groovy-ant-3.0.1.jar",
"org.codehaus.groovy=groovy-cli-picocli-3.0.1.jar",
"org.codehaus.groovy=groovy-console-3.0.1.jar",
"org.codehaus.groovy=groovy-datetime-3.0.1.jar",
"org.codehaus.groovy=groovy-docgenerator-3.0.1.jar",
"org.codehaus.groovy=groovy-groovydoc-3.0.1.jar",
"org.codehaus.groovy=groovy-groovysh-3.0.1.jar",
"org.codehaus.groovy=groovy-jmx-3.0.1.jar",
"org.codehaus.groovy=groovy-json-3.0.1.jar",
"org.codehaus.groovy=groovy-jsr-3.0.1.jar",
"org.codehaus.groovy=groovy-macro-3.0.1.jar",
"org.codehaus.groovy=groovy-nio-3.0.1.jar",
"org.codehaus.groovy=groovy-servlet-3.0.1.jar",
"org.codehaus.groovy=groovy-sql-3.0.1.jar",
"org.codehaus.groovy=groovy-swing-3.0.1.jar",
"org.codehaus.groovy=groovy-templates-3.0.1.jar",
"org.codehaus.groovy=groovy-test-junit-3.0.1.jar",
"org.codehaus.groovy=groovy-test-3.0.1.jar",
"org.codehaus.groovy=groovy-testng-3.0.1.jar",
"org.codehaus.groovy=groovy-xml-3.0.1.jar"
]
It only works with a single line "org.codehaus.groovy=X.jar", but a bug prevents it to work with all of the library jars (Look at this issue on Github).
So you have multiple choices:
Use Java instead of Groovy
Wait for a new Groovy release, or new releases of plugins (modules-plugin, and a version of javafx-plugin that use this one internally)
Use old javafx configuration: dependencies are not module by default, and you have to specify manually in build.gradle that JavaFX dependencies should be considered as a module (check my "obsolete" answer to this question)

OSGi bundle build issue in Gradle

I have a simple use case of building an OSGi bundle using Gradle build tool. The build is successful if there are java files present in the build path, but it fails otherwise.
I am using 'osgi' plugin inside the gradle script and trying to build without any java files. The build always fails with following error:
Could not copy MANIFEST.MF to
I am sure there must be some way to do it in Gradle but not able to fine. Any idea what can be done to resolve this depending on your experience.
I ran into this today as well, and #Peter's fix didn't work for me (I hadn't applied the java plugin in the first place...). However, after hours of Googling I did find this thread, which helped me find the problem.
Basically, it seems that the error occurs (as Peter stated) when no class files are found in the jar - my guess is because the plugin then cannot scan the classes for package names on which to base all the Import and Export information.
My solution was to add the following to the manifest specification:
classesDir = theSourceSet.output.classesDir
classpath = theSourceSet.runtimeClasspath
In my actual build code, I loop over all source sets to create jar tasks for them, so then it looks like this:
sourceSets.each { ss ->
assemble.dependsOn task("jar${ss.name.capitalize()}", type: Jar, dependsOn: ss.getCompileTaskName('Java')) {
from ss.output
into 'classes'
manifest = osgiManifest {
classesDir = ss.output.classesDir
classpath = ss.runtimeClasspath
// Other properties, like name and symbolicName, also set based on
// the name of the source set
}
baseName = ss.name
}
}
Running with --stacktrace indicates that the osgi plugin doesn't deal correctly with the case where both the osgi and the java plugins are applied, but no Java code is present. Removing the java plugin should solve the problem.
I had the same issue also when java code was present.
Adding these two lines to the osgiManifest closure fixed the problem:
classesDir = sourceSets.main.output.classesDir
classpath = sourceSets.main.runtimeClasspath
-- erik

JVM-based scripting language with Maven dependency resolution

I am looking for a simple way write short shell scripts that call into jar files.
Having to keep track of (and installing) all those jar files for the runtime classpath partly defeats the purpose using a script (as opposed to building a runnable jar file in Eclipse). I'd like Maven (or something equivalent) to manage this.
Image:
#!/usr/bin/the-cool-shell
use org.apache.commons/lang/3.0.0
use org.json/json
import org.json.*;
new JSONObject("{}");
And this should get the required artifacts from Maven automatically (at basically zero overhead after downloading it for the first time).
What are my options?
If you were using Groovy and Groovy Shell you could be using the Grape infrastructure.
#!/usr/bin/env groovy
#Grab( 'log4j:log4j:1.2.14' )
import org.apache.log4j.Level
import org.apache.log4j.Logger
def logger = Logger.getLogger(GroovyShell.class)
Logger.rootLogger.level = Level.INFO
logger.info 'I am using the Log4j library by using Grape'
As for your exact example this would work:
#!/usr/bin/env groovy
#Grapes([
#Grab('org.apache.commons:commons-lang3:3.0'),
#Grab('org.json:json:20090211')
])
import org.json.*
new JSONObject('{}')
In this case I was using the Groovy syntax but ordinary Java syntax is also fine.
Taken from the Javadoc of #Grapes annotation:
Sometimes we will need more than one grab per class, but we can only add
one annotation type per annotatable node. This class allows for multiple
grabs to be added.
You could try Gradle, it's a build management tool, but it uses Groovy for its build scripts, and it uses the Maven dependency model. So your script could be a Gradle 'build' script, that just did something different than building software.

Can clang be told not to analyze certain files?

I'm trying to use clang to profile a project I'm working on. The project includes a rather large static library that is included in Xcode as a dependency.
I would really like clang to not analyze the dependencies' files, as it seems to make clang fail. Is this possible? I've been reading the clang documentation, and I haven't found it.
As a last resort, there is a brute force option.
Add this to the beginning of a file:
// Omit from static analysis.
#ifndef __clang_analyzer__
Add this to the end:
#endif // not __clang_analyzer__
and clang --analyze won't see the contents of the file.
reference: Controlling Static Analyzer Diagnostics
So, this isn't really an answer, but it worked well enough.
What I ended up doing was building the static library ahead of time, and then building the project using scan-build. Since there was already an up-to-date build of the static library, it wasn't rebuilt and thus wasn't scanned.
I'd still love to have a real answer for this, though.
Finally, in 2018 the option was implemented.
Use --exclude <path> [1] [2] option
--exclude
Do not run static analyzer against files found in this directory
(You can specify this option multiple times). Could be useful when
project contains 3rd party libraries.
I don't use XCode, but using scan-build in linux the following works for me. I my case, I want to run the static analysis on all first party, non-generated code. However, I want to avoid running it on third_party code and generated code.
On the command line, clang-analyzer is hooked into the build when scan-build sets CC and CXX environment variables to ccc-analyzer and c++-analyzer locations. I wrote two simple scripts called ccc-analyzer.py and c++-analyzer.py and hooked them in to the compile in place of the default. In these wrapper scripts, I simply looked at the path of the file being compiled and then run either the raw compiler directly (if I wish to avoid static analysis) or the c*-analyzer (if I wish for static analysis to occur). My script is in python and tied to my specific build system, but as an example that needs modification:
import subprocess
import sys
def main(argv):
is_third_party_code = False
for i in range(len(argv)):
arg = argv[i]
if arg == '-c':
file_to_compile = argv[i + 1]
if '/third_party/' in file_to_compile or \
file_to_compile.startswith('gen/'):
is_third_party_code = True
break
if is_third_party_code:
argv[0] = '/samegoal/bin/clang++'
else:
argv[0] = '/samegoal/scan-build/c++-analyzer'
return subprocess.call(argv)
if __name__ == '__main__':
sys.exit(main(sys.argv))
For Xcode users, you can exclude individual files from static analyzer by adding the following flags in the Target -> Build Phases -> Compile Sources section: -Xanalyzer -analyzer-disable-all-checks

Resources