Specialization of the variable by configuration type in premake - premake

I'm using premake5 with Visual Studio 2013 and try to link a third-party library to my project. Debug version of this library has the "d" suffix as usual. This is the sample script.
solution "MySln"
language "C++"
configurations { "debug", "release" }
d = ""
configuration "debug"
d = "d"
configuration "release"
d = ""
libicu = { "icuin%{d}", "icuuc%{d}" }
project "core"
kind "SharedLib"
location "core"
links(libicu)
files { "core/**.h", "core/**.cpp" }
But this script links in both configurations (debug and release) icuin.lib and icuuc.lib. If I remove d = "" assignment in configuration "release" block then the both configurations link icuind.lib and icuucd.lib libraries. It looks as if premake uses the latest seen definition of the variable in resolving of %{d} placeholder. How can I change my script to obtain the correct behavior? Thanks!

You can't mix variable assignments (which are evaluated at script evaluation time) and Premake configurations (which are assembled after all project scripts are run) like that.
One solution could be:
solution "MySln"
language "C++"
configurations { "debug", "release" }
filter "configurations:debug"
targetextension "d"
project "core"
kind "SharedLib"
location "core"
files { "core/**.h", "core/**.cpp" }
filter "configurations:debug"
links { "icuind", "icuucd" }
filter "configurations:release"
links { "icuin", "icuuc" }
If you have lots of libraries or do this often you can use a function for it:
project "core"
links_d { "icuin", "icuuc" }
function links_d(value)
filter("configurations:debug")
for i = 1, #value do
links (value[i] .. "d")
end
filter("configurations:release")
links (value)
filter("*")
end

Related

How to get outputs of one Rule item as inputs of another one?

I want to create automatic crossplatform installation builder for my project. For this reason I made this file myprojectpackage.qbs:
Product {
type: "mypackage"
Depends { name: "myproject" } // <- this one has type "application"
Depends { name: "applicationpackage" }
}
applicationpackage.qbs uses some submodules and looks like:
Module {
name: "applicationpackage"
Depends { name: "qtlibsbinariespackage" }
Depends { name: "3rdpartybinariespackage" }
Depends { name: "resourcepackage" }
}
All these modules try to find something and copy to package directory. After they finish, I have a folder with a portable version of application. Every module of this group have typical structure:
Module {
name: "somepackage"
Rule {
condition: qbs.targetOS.contains("windows")
multiplex: true
alwaysRun: true
inputsFromDependencies: ["application"]
Artifact {
filePath: "Copied_files.txt"
fileTags: "mypackage"
}
prepare: {
var cmdQt = new JavaScriptCommand()
// prepare paths
cmdQt.sourceCode = function() {
// copy some files and write to Copied_files.txt
}
return [cmdQt]
}
}
}
After portable folder package complete, I want to make a zip archieve. So, I need another Module, which will run after package modules. I think, that only way to do like this is taking .txt files, that were created by modules in applicationpackage, as inputs for another Rule.
I have tried a lot of things (FileTaggers, outputFileTags etc.), but noone worked properly. So is there any way to do make modules work in pipeline as I want to do?
Do I understand correctly that you want to "merge" the contents of the txt files tagged "mypackage" into the archive, i.e. everything listed in all the files is supposed to end up there?
If so, then you simply need a "top-level" rule that does the aggregation. Your existing rules would tag their outputs as e.g. "mypackage.part" and then a multiplex rule would take these as inputs and create a "mypackage" artifact.
Note that there is the archiver module (https://doc.qt.io/qbs/archiver-module.html) that can do the final step of creating the package for you from the aggregated txt file.

JavaFX packager - can the name of the package icon be specified?

For a couple of years, I have been releasing updates to a modest app on a yearly basis -- just before the summer swim league starts up.
In the past, I have specified the various icons (volume, app, etc.) by placing them in the package/macosx/ folder. The filenames, MyApp-volume.icns etc., matched the <fx:application name="MyApp" .../> and everything worked just fine.
But starting with this year's build and deployment, the app's name will contain the year -- i.e., MyApp 2016. However, I don't want to be changing the icon filenames each year; I would like to keep them as they are (MyApp-volume.icns, MyApp.icns).
Is there a way to tell the Java packager to use a specific icon filename, one that is different from that of the app name or title? (I have looked at Oracle docs, but I don't see anything.)
-Bicon=<path to icon relative to project resourses>
is this what you looking for?
or you could just add it to your main app Stage.
hope it is usefull
As I wrote in my first comment to my question, javapackager doesn't have an option to do this.
Here's the solution that I worked out:
Create a new folder at the same level as the folder package (this doesn't refer to Java package but to Custom Resources). Name the new folder package-base.
Move the macosx and windows folders from package to package-base. (I don't produce an executable for Linux because none of my users use Linux.) Now, the package folder is empty.
In my build script, I added a step which, for every build that produces a "self-contained application package" (Oracle's terminology), cleans the package folder, and then copies the contents of package-base to package.
The files are renamed as they are copied to include the desired wording -- in my case, that means the year is appended to the filename. For example, MyApp-volume.icns when copied is renamed MyApp-2018-volume.icns.
Here are the relevant Gradle snippets:
import org.gradle.internal.os.OperatingSystem
...
def getYear() {
new Date().format('yyyy')
}
...
ext {
...
year = getYear()
appNameBase = "MyApp"
appName = appNameBase + " " + year
...
}
...
task macCleanPackage {
doLast {
if (OperatingSystem.current().isMacOsX()) {
delete fileTree(dir: "./package/macosx", include: "*.*")
}
}
}
task macCopyAndRenamePackageResources {
dependsOn macCleanPackage
doLast {
if (OperatingSystem.current().isMacOsX()) {
def toDir = "./package/macosx"
copy {
from './package-base/macosx'
into "${toDir}"
include "*${appNameBase}*.*"
rename { String fileName -> fileName.replace("$appNameBase", "${appName}") }
}
ant.replaceregexp(file: "${toDir}/${appName}-dmg-setup.scpt", match:"${appNameBase}", replace:"${appName}", flags:'g')
}
}
}
task windowsCleanPackage {
doLast {
if (OperatingSystem.current().isWindows()) {
delete fileTree(dir: "package/windows", includes: ["*.bmp", "*.ico", "*.iss"])
}
}
}
task windowsCopyAndRenamePackageResources {
dependsOn windowsCleanPackage
doLast {
if (OperatingSystem.current().isWindows()) {
def toDir = "./package/windows"
copy {
from './package-base/windows'
into "${toDir}"
include "*${appNameBase}*.*"
rename { String fileName -> fileName.replace("$appNameBase", "${appName}") }
}
// Replace app name in iss setup script to include year.
def issFilename = "./package/windows/${appName}.iss"
ant.replaceregexp(file: "${issFilename}", match: "${appNameBase}", replace: "${appName}", flags: "g")
ant.replaceregexp(file: "${issFilename}", match: "AppCopyright=Copyright (C)", replace: "AppCopyright=Copyright (C) ${year}", byline: "on")
ant.replaceregexp(file: "${issFilename}", match: "AppVersion=", replace: "AppVersion=${year} build ${buildNumber}", byline: "on")
ant.replaceregexp(file: "${issFilename}", match: "OutputBaseFilename=.*", replace: "OutputBaseFilename=${appName}-(build ${buildNumber})", byline: "on")
}
}
}
I don't just change filenames.
For the OS X release, ant.replaceregexp is used to modify the app's name in the custom AppleScript file.
For the Windows release, ant.replaceregexp is used extensively to replace version numbers, copyright, as well as the application's name (including the year) in the InnoSetup configuration file.
It may seem like a lot of extra work, but once the script is written, it just works.

Premake "no active solution, project or configuration" error

I am trying to run premake with custom script like this
premake4.exe -file=proj4_shared.lua vs2010
And I get
proj4_shared.lua:2: no active solution, project, or configuration
Contens of the proj4_shared.lua:
#!lua
solution ("Proj4")
project "proj4"
language "C++"
kind "SharedLib"
files { "proj4/*.h", "src/src/*.c", "src/src/proj4.def" }
excludes { "src/src/cs2cs.c", "src/src/geod.c", "src/src/nad2bin.c", "src/src/nad2nad.c" }
location (BUILD_DIR .. "vcproj")
includedirs { "src/src" }
defines { "WIN32", "_CRT_SECURE_NO_WARNINGS" }
buildoptions { "/W1" }
local p = project()
p.uuid = GetExistingUuid(p) or p.uuid
configuration { "Debug*" }
defines { "_DEBUG", "DEBUG" }
flags { "Symbols" }
targetsuffix "D"
configuration { "Release*" }
defines { "NDEBUG" }
flags { "Optimize" }
if (not DISABLE_RELEASE_SYMBOLS) then flags { "Symbols" } end
targetsuffix ""
According to https://github.com/premake/premake-4.x/wiki/solution
The solution function creates a new solution and makes it active
So what is the issue?
I recommend you try:
solution ("Proj4")
local p = project "proj4"
...
I suspect the call to project() with no argument is confusing the system.
ALTERNATIVELY:
You can try:
local p = premake.api.current.project
Which should also work to get you a reference to the current project.
NOTE: I am using premake5.exe, not premake 4, so some things may have changed in the interim.

How to pass _OPTIONS to included premake4 scripts?

I've got a main premake4.lua script:
solution "MySolution"
language "c++"
newoption = {
trigger = "my-option",
description = "This is an option"
}
include "../my_library"
I would like to pivot logic in the included script ( ../my_library/premake4.lua ) based on the contents of _OPTIONS:
if _OPTIONS["my-option"] then
project "myStaticLibrary"
kind "StaticLib"
else
project "mySharedLibrary"
kind "SharedLib"
end
files "foo.cpp"
How to get _OPTIONS in the scope of the included premake4 script?
You don't need to do anything. _OPTIONS is a global variable and will be accessible to all of your scripts automatically. Are you seeing otherwise?
I'm answering my own question just in case anyone else is tempted to solve things in the same way. I was Doing It Wrong. After struggling with it my final solution defined multiple configurations:
-- the main script
solution "MySolution"
language "c++"
configurations { "Release", "Debug", "ReleaseDLL", "DebugDLL" }
configuration { "Release", "ReleaseDLL" }
flags { "Optimize" }
configuration { "Debug", "DebugDLL" }
flags { }
defines {"_DEBUG=1"}
configuration {}
include "../my_library"
The included script specified the kind according to configuration:
-- the included script
project "myStaticLibrary"
configuration { "*" }
kind "StaticLib"
configuration { "*DLL" }
kind "SharedLib"
configuration {}
files "foo.cpp"
And to to build the right targets the config is specified at the make:
premake4 gmake
cd gmake
make config=release
make config=debug
make config=releasedll
make config=debugdll

Cleanest way in Gradle to get the path to a jar file in the gradle dependency cache

I'm using Gradle to help automate Hadoop tasks. When calling Hadoop, I need to be able to pass it the path to some jars that my code depends on so that Hadoop can send that dependency on during the map/reduce phase.
I've figured out something that works, but it feels messy and I'm wondering if there's a feature I'm missing somewhere.
This is a simplified version of my gradle script that has a dependency on the solr 3.5.0 jar, and a findSolrJar task that iterates through all of the jar files in the configuration to find the right one:
apply plugin: 'groovy'
repositories {
mavenCentral()
}
dependencies {
compile 'org.apache.solr:solr-solrj:3.5.0'
}
task findSolrJar() {
println project.configurations.compile*.toURI().find { URI uri -> new File(uri).name == 'solr-solrj-3.5.0.jar'}
}
running this gives me output like this:
gradle findSolrJar
file:/Users/tnaleid/.gradle/caches/artifacts-8/filestore/org.apache.solr/solr-solrj/3.5.0/jar/74cd28347239b64fcfc8c67c540d7a7179c926de/solr-solrj-3.5.0.jar
:findSolrJar UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.248 secs
Is there a better way to do this?
Your code can be simplified a bit, for example project.configurations.compile.find { it.name.startsWith("solr-solrj-") }.
You can also create a dedicated configuration for an artifact, to keep it clean; and use asPath if the fact that it can potentially return several locations works well for your use case (happens if it resolves same jar in several locations):
configurations {
solr
}
dependencies {
solr 'org.apache.solr:solr-solrj:3.5.0'
}
task findSolrJars() {
println configurations.solr.asPath
}
To avoid copy-paste, in case you as well need that jar in compile configuration, you may add this dedicated configuration into compile one, like:
dependencies {
solr 'org.apache.solr:solr-solrj:3.5.0'
compile configurations.solr.dependencies
}
I needed lombok.jar as a java build flag to gwt builds this worked great !
configurations {
lombok
}
dependencies {
lombok 'org.projectlombok:lombok+'
}
ext {
lombok = configurations.lombok.asPath
}
compileGwt {
jvmArgs "-javaagent:${lombok}=ECJ"
}
I was surprised that the resolution worked early enough in the configuraiton phase, but it does.
Here is how I did it:
project.buildscript.configurations.classpath.each {
String jarName = it.getName();
print jarName + ":"
}
I recently had this problem as well. If you are building a java app, the problem at hand is normally that want to get the group:module (groupId:artifactId) to path-to-jar mapping (i.e. the version is not a search criteria as in one app there is normally only one version of each specific jar).
In my gradle 5.1.1 (kotlin-based) gradle build I solved this problem with:
var spec2File: Map<String, File> = emptyMap()
configurations.compileClasspath {
val s2f: MutableMap<ResolvedModuleVersion, File> = mutableMapOf()
// https://discuss.gradle.org/t/map-dependency-instances-to-file-s-when-iterating-through-a-configuration/7158
resolvedConfiguration.resolvedArtifacts.forEach({ ra: ResolvedArtifact ->
s2f.put(ra.moduleVersion, ra.file)
})
spec2File = s2f.mapKeys({"${it.key.id.group}:${it.key.id.name}"})
spec2File.keys.sorted().forEach({ it -> println(it.toString() + " -> " + spec2File.get(it))})
}
The output would be some like:
:jing -> /home/tpasch/scm/db-toolchain/submodules/jing-trang/build/jing.jar
:prince -> /home/tpasch/scm/db-toolchain/lib/prince-java/lib/prince.jar
com.github.jnr:jffi -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jffi/1.2.18/fb54851e631ff91651762587bc3c61a407d328df/jffi-1.2.18-native.jar
com.github.jnr:jnr-constants -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jnr-constants/0.9.12/cb3bcb39040951bc78a540a019573eaedfc8fb81/jnr-constants-0.9.12.jar
com.github.jnr:jnr-enxio -> /home/tpasch/.gradle/caches/modules-2/files-2.1/com.github.jnr/jnr-enxio/0.19/c7664aa74f424748b513619d71141a249fb74e3e/jnr-enxio-0.19.jar
After that, it is up to you to do something useful with this Map. In my case I add some --path-module options to my Java 11 build like this:
val patchModule = listOf(
"--patch-module", "commons.logging=" +
spec2File["org.slf4j:jcl-over-slf4j"].toString(),
"--patch-module", "org.apache.commons.logging=" +
spec2File["org.slf4j:jcl-over-slf4j"].toString()
)
patchModule.forEach({it -> println(it)})
tasks {
withType<JavaCompile> {
doFirst {
options.compilerArgs.addAll(listOf(
"--release", "11",
"--module-path", classpath.asPath
) + patchModule)
// println("Args for for ${name} are ${options.allCompilerArgs}")
}
}
}

Resources