How can I build sbt against RPM-installed (system) libraries? - sbt

I'm interested in building an RPM package for sbt 0.12.3 that meets the Fedora packaging guidelines. In order to do this, I'll need to be able to build sbt itself against libraries that were built from source and installed via RPM packages.
Java packages in Fedora that use Ivy are able to resolve RPM-installed artifacts by disabling network resolvers and resolving all packages from /usr/share/java/[artifact].[ext] -- see here for an example.
I think I understand how to override default resolvers in sbt using a boot properties file, but this is where I run in to a problem: if I set the Ivy directory to /usr/share/java, sbt expects to be able to publish artifacts to this directory (not merely to look for existing artifacts there), which I don't want it to do (both in general and for this specific case of RPM building). If I specify file:///usr/share/java as a proxy location (following Mark's instructions below), sbt will fail (citing the absence of ivy.xml in that location).
I am able to find locally-installed dependencies by modifying project/p.sbt to point to explicit URLs (e.g. "org.jsoup" % "jsoup" % "1.7.1" from "file:///usr/share/java/jsoup.jar"), but this doesn't work for scala and the scala library (and is obviously not the right thing to do in general).
How can I build sbt against (and only against) locally-installed, RPM-managed system Scala and libraries?

Related

Conan-based Qt installation uses wrong home dir for linking

I'm trying to build our application using Qt 5.13.0 installed via Conan/Artifactory. We run our own Artifactory server and the Qt version there is self-build (and statically linked) in our CI solution. We use the Conan recipe for Qt written by the bincrafters, slightly modified to apply some patches for known Qt bugs and set some flags for building properly on Android and WebAssembly.
When trying to build the application, the linker fails to find the necessary dependencies for Qt itself because it tries to look them up in the home folder of the user who build the Qt package, not the user who's running the build.
Here's an excerpt from the build log, showing the attempt at linking all previously compiled object files together:
application folder-------v subproject of the application----v-------v dependency of the application, correct user home dir---------v Qt library installed via Conan, correct user home dir-------v dependency of Qt, WRONG user home dir------------v
g++ -Wl,--gc-sections -o ../../fah [--> all the .o files <--] -L../lib -lmodel -lcore [--> more linked libraries and application parts <--] -L/home/kaupes/.conan/data/libsodium/1.0.18/bje/stable/package/d1efe3774eed76670888f919621e7c4e1b52efa9/lib /home/kaupes/.conan/data/qt/5.13.0/bje/stable/package/d6b3f512e1a5607061462f94e3271dc8af3dd516/lib/libQt5Gui.a /home/dev/.conan/data/harfbuzz/2.4.0/bje/stable/package/c68551ae35bf5d62e66263379d58a38416eb84a9/lib/libharfbuzz.a [--> many, many more libraries <--]
g++: error: /home/dev/.conan/data/harfbuzz/2.4.0/bje/stable/package/c68551ae35bf5d62e66263379d58a38416eb84a9/lib/libharfbuzz.a: No such file or directory
many, many more errors...
As you can see, the user running the build is kaupes, but the g++ invocation attempts to look for the dependencies in /home/dev/, the home folder of the CI user who build the Qt Conan package.
Only dependencies of Qt itself have the problem. Dependencies of the application (also installed via Conan) are found at the correct place.
The Qt package has been build in the CI using the following Conan invocation:
conan create --profile .conan/profiles/linux -s compiler=gcc -s compiler.version=9 . fah/stable
Compiler and version are explicitly set because I'm also build for another GCC version. The linux profile file also doesn't do anything interesting (as far as I can see):
include(default)
[settings]
build_type=Release
compiler.libcxx=libstdc++11
[options]
OpenSSL:shared=False
OpenSSL:no_asm=True
OpenSSL:no_asm=True
OpenSSL:no_weak_ssl_ciphers=True
OpenSSL:no_ssl2=True
OpenSSL:no_ssl3=True
OpenSSL:no_engine=True
libcurl:shared=False
libxml2:shared=False
libxml2:fPIC=True
libsodium:shared=False
pcre2:shared=False
libpng:shared=False
freetype:shared=False
bzip2:shared=False
libjpeg:shared=False
harfbuzz:shared=False
xkbcommon:shared=False
qt:shared=False
qt:with_glib=False
qt:with_sqlite3=False
qt:with_mysql=False
qt:with_pq=False
qt:with_odbc=False
qt:with_sdl2=False
qt:with_openal=False
qt:with_libalsa=False
qt:openssl=True
qt:commercial=False
qt:qtsvg=True
qt:qtdeclarative=True
qt:qtactiveqt=False
qt:qtscript=False
qt:qtmultimedia=False
qt:qttools=True
qt:qtxmlpatterns=False
qt:qttranslations=True
qt:qtdoc=False
qt:qtrepotools=False
qt:qtqa=False
qt:qtlocation=True
qt:qtsensors=True
qt:qtwayland=True
qt:qt3d=False
qt:qtimageformats=False
qt:qtgraphicaleffects=True
qt:qtquickcontrols=True
qt:qtserialbus=False
qt:qtserialport=False
qt:qtx11extras=True
qt:qtmacextras=False
qt:qtwinextras=False
qt:qtandroidextras=False
qt:qtwebsockets=True
qt:qtwebchannel=False
qt:qtwebengine=False
qt:qtwebview=False
qt:qtquickcontrols2=True
qt:qtpurchasing=False
qt:qtcharts=True
qt:qtdatavis3d=False
qt:qtvirtualkeyboard=True
qt:qtgamepad=False
qt:qtscxml=False
qt:qtspeech=False
qt:qtnetworkauth=False
qt:qtremoteobjects=False
qt:qtwebglplugin=False
qt:qtlottie=False
qt:qtconnectivity=True
Is there something I'm doing wrong during the Conan package creation or installation or is this caused by something different?
Indeed, when building qt, all paths to dependencies are hardcoded in configurations files (mkspecs\modules\qt_lib_*.pri).
I assume you are building your application with qmake, because you use static qt, and static qt is incompatible with cmake. One thing you could try is to pass the full path to harfbuzz lib to qmake by adding argument QMAKE_LIBS_HARFBUZZ=/home/kaupes/.conan/data/harfbuzz/2.4.0/bje/stable/package/c68551ae35bf5d62e66263379d58a38416eb84a9/lib/libharfbuzz.a to your qmake invocation.
Edit: it seems to be a knwonw behaviour of qt >= 5.12.1 : https://bugreports.qt.io/browse/QTBUG-72903. This feature has been reverted in 5.14.x and 5.15.x with https://github.com/qt/qtbase/commit/9864d2c6f3b628ca9f07a56b197e77bd43931cca

Run SBT without installing it first

I was wondering if SBT has something similar to the Gradle Wrapper?
I would like to use it on a CI server without having to install SBT first.
The documentation mentions a sbt-launcher, but that seems to be geared towards running actual application instead of builds.
Yes, sbt-extras is a bash script that you can commit to your repository to act like the gradle wrapper.
The sbt-extras project is centered around a stand-alone script called sbt which can be directly used to run sbt without having it on the machine first.
The script has logic to determine the proper version of sbt for the project, download the correct version of the sbt jar, and then run the tasks through sbt.
If you copy the sbt script into your project, you can simply call it — from your CI server, locally, or wherever — to run sbt tasks without needing sbt installed separately.

Downloading source jars in sbt?

I pulled down the sources and build/published it locally. I want to debug into sources jars. When I publish it locally, I clearly see it also publishes source jars.
[info] published securesocial-testkit_2.10 to local\ws.securesocial\securesocial-testkit_2.10\master-SNAPSHOT\srcs\securesocial-testkit_2.10-sources.jar
I don't know how to reference this jar.
Changing "ws.securesocial" %% "securesocial" % "master-SNAPSHOT" to "ws.securesocial" %% "securesocial" % "master-SNAPSHOT-sources" doesn't work.
Add withSources() to the dependency definition.
From Download Sources in the official documentation of sbt:
Downloading source and API documentation jars is usually handled by an
IDE plugin. These plugins use the updateClassifiers and
updateSbtClassifiers tasks, which produce an Update Report referencing
these jars.
To have sbt download the dependency's sources without using an IDE
plugin, add withSources() to the dependency definition. For API jars,
add withJavadoc(). For example:
libraryDependencies += "org.apache.felix" % "org.apache.felix.framework" % "1.8.0" withSources() withJavadoc()
Note that this is not transitive. Use the update-*classifiers tasks
for that.
You can also run sbt update-classifiers to download sources and javadoc jars for all project dependencies at once
For sbt 1.0, command is sbt updateClassifiers
For me, it worked better with
sbt ';reload plugins; updateClassifiers'

How to run a Qt application on a system where Qt is not installed?

I have made an application using QtWebKit, Qt4. I have the binary generated in Fedora 16. Now, I want to run that application on another PC (running some other Fedora version), where Qt is not installed. How can I package my Qt application so that it can run on a platform where Qt is not installed? Is there any command line utility as well as QtCreator utility to do so. I have tried "deploy all" command, but it didn't have any affect.
Create an Installer with the Qt Installer Framework and just supply all needed shared libraries (Win/OSX) or compile statically. Under Linux there is always the problem between system-wide libraries or bundled libraries. The documentation https://qt-project.org/doc/qt-5.0/qtdoc/deployment.html should give you a good start
Obviously, you need to have access to the qt libraries, which are exactly the same version that you used to compile your application.
There are two options :
link qt libraries statically
create a RPM package (see this how)
Also check Deploying Qt Applications.
Since you're deploying using rpm, to systems where Qt 4 rpms are available, you don't need to do anything besides simply adding a dependency on the qt to your rpm's specfile. The user installing your package using yum localinstall will get the Qt dependencies automatically installed. That's the correct way of doing it - it will keep your package size small.
Of course you need a separate rpm build for every fedora/centos major version out there, but that's almost always a requirement.
If your package needs newer Qt version than the one provided by the platform packages, you can still make a specific version dependency (say qt >= 4.7.0) and have a readme that indicates that newer packages can be obtained from a 3rd party repository (epel etc.)
For deployment under Linux I've used Bitrock Installer Tool.
The main thing before deploying is to check your dependencies. You can do that by using command:
ldd appName | grep libQt
After that you'll see list of dependencies. You'll have to set environment variable LD_LIBRARY_PATH to let linker know where're your libraries. To do that:
export LD_LIBRARY_PATH=.
. means current directory
And after that:
./appName $*
After that you'll be able to use your executable with Bitrock Installer Tool.

How can SBT project import library from GitHub cloned to local directory?

I forked a Scala library from GitHub, and I want to import it to another project.
How can I tell sbt where to find this package?
For example, I'm writing a program in ~/code/scala/myProgram, and I want to import a library from ~/code/scala/otherlib.
If it is supported by the project you have cloned (that is, if it supports SBT and is configured to publish to a repository), you can publish it locally with the sbt command sbt publish-local. For example:
cd ~/code/scala/otherlib
sbt publish-local
This will build and publish this library in your local Ivy repository (typically ~/.ivy2/local). Note that you will need to repeat this each time you modify the otherlib sources.
After the project's published locally to the local Ivy repository, you can specify otherlib as a dependency in your SBT project, using the regular SBT dependency for the original version of the forked library (assuming that you haven't changed its ID, version, group ID, etc.). For example, by adding:
libraryDependencies += "com.some_company" % "otherlib" % "1.0.0"
to your build.sbt file.
Now, when you build your project, it will find otherlib in your local Ivy repository (as if it'd been pulled down from a regular repository) and will use your custom version of it.
If otherlib doesn't support SBT, or isn't configured to publish to a repository, and you do not want to modify it to do so, then you can simply copy its .jar file(s) to the /lib directory (~/code/scala/myProgram/lib) of your project.
SBT supports git repositories out of the box. The support is for clone and checkout. See my answer to Can SBT refresh git uri dependency (always or on demand)? or Using Git local repository as dependency in SBT project?, that boil down to the following in build.sbt:
lazy val gitRepo = "git:file:///Users/jacek/sandbox/so/sbt-git/git-repo/#master"
lazy val g = RootProject(uri(gitRepo))
lazy val root = project in file(".") dependsOn g
Once you define the dependency (between projects) you can use it - the git-hosted project - with no other configuration.

Resources