I'm writing an application with JavaFX and am concerned about the size of the .EXE file that I'll be natively deploying. The application that I have is not so big (all together less than 5M), but the Java Runtime is making the final installed directory well over 100M which compresses into a ditributable 44M file.
I've been running tests with 64-bit Windows (Java SE 8u77). To make the final executable smaller I've removed parts of the JRE that are unnecessary as outlined here: http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html
Here's what I've found:
Complete JRE : 45.0 M
Stripped JRE : 44.0 M
Does anyone have any ideas on how to make the distributable .EXE even smaller? All of the information I've found is at least 2 or 3 years old and maybe not so relevant anymore. I'm feeling like there's more that can come out of the JRE, but it seems that that would violate the licensing.
Does anyone have any experience using any non-Oracle distributions or any other ways to make the JavaFX app smaller?
When using the javapackager, you can set to NOT include the JRE. This makes the native launcher use the local installed JRE (which might not be the best solution).
When using the javafx-maven-plugin, you just have to set a bundlerArgument:
<configuration>
<mainClass>com.zenjava.test.Main</mainClass>
<bundleArguments>
<runtime /> <!-- dont include JRE, use installed one -->
</bundleArguments>
</configuration>
When using the javafx-gradle-plugin, just set the runtime as NULL:
jfx {
verbose = true
mainClass = 'your.application.appname'
appName = 'appname'
jfxMainAppJarName = 'appname.jar'
vendor = "My Company"
bundleArguments = [
runtime: null
]
}
When using the ant-style xml-file of the javapacker itself, just set this:
<fx:bundleArgument name="runtime" value="" />
Disclaimer: I'm the maintainer of the javafx-maven-plugin and the creator of the javafx-gradle-plugin.
One of the best tools for this is Proguard.
Run your program through it before generating an executable
Related
As part of installation of a WPF application using .NET 6 and a WiX installer, I would like to check whether the .NET 6 runtime is installed.
WiX provides pre-defined properties to check this for .NET framework but nothing for .NET Core and beyond so I am attempting to check for the presence of a registry key.
There is a registry key that can be checked under: HKEY_LOCAL_MACHINE\SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedhost\Version
However, if I uninstall the runtime the registry key does not get removed, is there any other reliable way to check whether the runtime is installed, as well as which version is installed?
WiX 3 currently doesn't handle this natively. It is being worked on for WiX v4 (GitHub issue). Reading the issue led me to these tools as a current workaround.
https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x86
https://www.nuget.org/packages/Microsoft.NET.Tools.NETCoreCheck.x64
You can use the files inside of these packages to check for a runtime. Either by running NetCoreCheck.exe directly or using the custom action DLL provided.
NetCoreCheck.exe -h to see help. But you'll want something like this:
netcorecheck --runtimename Microsoft.NetCore.App --runtimeversion 6.0.0
I don't know how to use the custom action dll but I do see it has two DLL exports.
ordinal hint RVA name
1 0 00001500 CheckNETRuntime
2 1 00002260 get_hostfxr_path
You may use the Custom Action DLL mentioned in Hank's answer if you want to integrate this in your WiX project.
You can use the NuGet package to obtain the dll.
Unfortunately there seems to be no documentation in existence for this DLL, so I used the source code to figure out how this works.
First you need to define a few properties that are used as input parameters for the .NET runtime check, and for the result of the check.
<Property Id="CheckNETRuntime_Framework" Value="Microsoft.AspNetCore.App" />
<Property Id="CheckNETRuntime_Version" Value="6.0.0" />
<Property Id="CheckNETRuntime_Result" />
CheckNETRuntime_Framework is the framework to search for. There are currently 3 options:
Microsoft.NETCore.App
Microsoft.AspNetCore.App
Microsoft.WindowsDesktop.App
CheckNETRuntime_Version is the version of .NET to look for.
The result will be stored in CheckNETRuntime_Result. A value of 0 indicates the runtime was found, any other value indicates it was not found.
To run the custom action, do this:
<Binary Id="CustomActions" SourceFile="NetCoreCheckCA.dll" /> <!-- This should be the path to the dll -->
<CustomAction Id="CheckRuntime" Return="ignore" BinaryKey="CustomActions" DllEntry="CheckNETRuntime" />
<InstallExecuteSequence>
<Custom Action="CheckRuntime" Before="LaunchConditions" />
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="CheckRuntime" Before="LaunchConditions" />
</InstallUISequence>
Note: you need to add Return="ignore" if you do not want the installer to fail when the runtime was not found (as the return value if not 0, which indicates a failure).
The CheckNETRuntime_Result property can be used elsewhere in your setup, for example you could use it in a condition:
<Condition Message=".NET 6 runtime is not installed">
<![CDATA[CheckNETRuntime_Result=0]]>
</Condition>
How can I update the jar files to the latest version which comes with coldfusion installation? I can see jar files, with different versions, under different locations. How can I confirm which version of the jar is currently running and what are the locations ColdFusion looks for these jars?
For example, in coldfusion\lib I have these jars:
commons-collections.jar
commons-collections.3.1.jar
commons-collections.3.2.jar
Then in another location \Coldfusion\cfusion\lib, I have:
commons-collections.jar
Thanks in advance for any help or suggestions.
what are the locations coldfusion looks for these jars
Generally, ColdFusion searches the following locations for jars:
ColdFusion Class Path (See ColdFusion Administrator > Server Settings > Java & JVM).
Default JVM class path
Dynamic paths specified in THIS.javaSettings (CF10+ only)
what version of the jar in currently running
Usually you can identify the source jar by picking a class likely to exists all versions of that library and checking it with Class.getResource(). For that specific library, CollectionUtils would probably be a good choice, since the API says it has existed since version 1.0.
// Create instance
testClass = createObject("java", "org.apache.commons.collections.CollectionUtils").getClass();
// Convert class name to format: /path/to/TheClassName.class
className = "/"& replace( testClass.name, ".", "/", "all") &".class";
// Display location, or "null" if unknown
location = testClass.getResource( className );
writeOutput( isNull(location) ? "null" : location.toString());
The results will obviously vary, but with my ColdFusion 11 install, the above returns:
org/apache/commons/collections/CollectionUtils.class
jar:file:/c:/ColdFusion/cfusion/lib/commons-collections-3.2.1.jar!/org/apache/commons/collections/CollectionUtils.class
I'd like to install liip/imagine-bundle in my symfony 2 project. But in order to make barcodes, I installed previously MopaBarcodeBundle.
MopaBarcodeBundle requires "avalanche123/imagine-bundle" which requires imagine/imagine: v0.4.1
And
LiipImagineBundle requires imagine/imagine: ~0.5,<0.7
Obviously composer detects the conflict, as he cannot unistall v0.4.1, and that version is not enough for LiipImagine.
I'd like to know how I could bypass this. Create sorts of aliases in composer and keep the two versions on my project ? I'm not a pro in version management, so I guess this is not possible.
Thank you very much for any help.
Ok, after some code inspection i figured out a way around. MopaBarcodeBundle doesn't really requires avalanche123/imagine-bundle, but it uses it in the service declaration. (To make the link with Imagine classes).
So I changed the service.xml file containing the BarcodeService declaration.
<parameter key="imagine.gd.class">Imagine\Gd\Imagine</parameter>
<service id="imagine" alias="imagine.gd" />
<service id="imagine.gd" class="%imagine.gd.class%" />
I guess thoses lines could be factorised, but i chose to keep it as it was done in avalanche123.
Also a constant from avalanche was used in 5th argument, I changed it to :
<argument>%kernel.root_dir%../web</argument>
Finally I removed avalanche, and then install a newer version of imagine/imagine
I'm trying to deploy an ASP.NET web application to Azure. It's hybrid Web Forms, MVC, and WebAPI, and there are a TON of aspx/ascx files, such that they really need to be precompiled or every deploy will render the site sluggish for awhile.
I am trying to deploy via SCM integration with GitHub via kudu, with precompiled views, all merged to a single assembly.
Note that:
Deploy works fine with precompilation disabled.
Deploy works fine from Visual Studio
Build works fine if I copy the msbuild command from the Azure log, replace the relevant paths, and run it locally on my Windows 8.1 machine.
I've set up the Advanced Precompile settings as:
Don't allow precompiled site to be udpatable
Don't emit debug information
Merge all pages and control outputs to a single assembly = AppViews.dll
Here's the .deployment file for Azure
[config]
project = WebSite/WebSite.csproj
SCM_BUILD_ARGS=/p:Configuration=Release;PublishProfile=azure-prod /v:n
You notice I'm sending the verbosity /v to "normal" for extra diagnostic information.
Here is info I get toward the tail of the deployment log:
AspNetPreCompile:
D:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v \ -p D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\Source -c D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir
GenerateAssemblyInfoFromExistingAssembleInfo:
Creating directory "obj\Release\AssemblyInfo".
D:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /out:obj\Release\AssemblyInfo\AssemblyInfo.dll /target:library Properties\AssemblyInfo.cs
AspNetMerge:
Running aspnet_merge.exe.
D:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\aspnet_merge.exe D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir -w AppViews.dll -copyattrs obj\Release\AssemblyInfo\AssemblyInfo.dll -a
aspnet_merge : error 1003: The directory 'D:\home\site\repository\WebSite\obj\Release\AspnetCompileMerge\TempBuildDir' does not exist. [D:\home\site\repository\WebSite\WebSite.csproj]
Done Building Project "D:\home\site\repository\WebSite\WebSite.csproj" (Build;pipelinePreDeployCopyAllFilesToOneFolder target(s)) -- FAILED.
Build FAILED.
It looks like aspnet_compiler.exe runs, but doesn't do what it's supposed to, which is why the TempBuildDir directory (supposed to be the output of the compiler) does not exist in time for the AspNetMerge target. Contrast that with my system, where that directory DOES in fact exist, containing the marker aspx/ascx/etc. files, static content, a PrecompiledApp.config file, and a whole mess of stuff in the bin directory.
aspnet_compiler.exe has an -errorstack flag but it's not clear to me how I could get MSBuild to add this just via the .deployment file, or even if that app is really even throwing an error.
I could just deploy via Visual Studio, but I would really like to take advantage of the SCM integration so I can just push to my prod branch and let it go. Any suggestions?
I replied on https://github.com/projectkudu/kudu/issues/1341, but copying my answer here in case someone lands here...
Way back, we had found that aspnet_compiler.exe was not working within Azure Websites due to how it dealt with the profile folder. We made a change at the time that's a bit of a hack but got us going: we turned it into a no-op, by pointing HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\aspnet_compiler.exe to our own dummy exe (D:\Program Files (x86)\aspnet_compiler\KuduAspNetCompiler.exe).
But trying it now, it appears to work correctly today, likely thanks to improvements in the Azure Websites hosting environment. So we will try getting rid of this hack and doing a full test pass to make sure it doesn't cause any major regressions. If all goes well, we can get that into production, which should enable those scenarios.
In the short term, you may be able to work around this by having your build script:
copy aspnet_compiler.exe from D:\Windows\Microsoft.NET\Framework\v4.0.30319 into your own site files, but under a different name (e.g. aspnet_compiler2.exe)
convince msbuild to use that one
Note: This GitHub issue on projectkudu will eventually make this solution obsolete, but for the meantime, that issue is filed as Backlog, and this works right now.
Thank you thank you David Ebbo. With this information, I was able to bootstrap my build to work for the short term.
First, I downloaded the aspnet_compiler.exe from the Azure instance using the Diagnostic Console available at https://{WEBSITE_NAME}.scm.azurewebsites.net/DebugConsole and added that to my own repository. This way there's no question about any difference between 32/64-bit, etc. I renamed it to azure_aspnet_compiler.exe in my repository.
Second, the AspNetCompiler task doesn't give you the option to change the tool name. It's hardcoded, but as a virtual property so it's overrideable. So I had to create my own task class, and package it in its own assembly, which I built in Release mode and also included in my repository.
public class AzureAspNetCompiler : Microsoft.Build.Tasks.AspNetCompiler
{
private string _toolName = "aspnet_compiler.exe";
protected override string ToolName
{
get { return _toolName; }
}
public string CustomToolName // Because ToolName cannot have a setter
{
get { return _toolName; }
set { _toolName = value; }
}
}
Next I needed to replace the AspNetPreCompile task in MSBuild, but I couldn't figure out how to do that directly. But that task wasn't doing anything anyway, so why not just run right after it?
I added this to the top of my Website.csproj file to import the DLL containing the AzureAspNetCompiler class. Note that the path is relative to the Website.csproj file I'm editing.
<UsingTask TaskName="AzureBuildTargets.AzureAspNetCompiler"
AssemblyFile="..\DeploymentTools\AzureBuildTargets.dll" />
Then I added this right below it, which is basically stealing the MSBuild target definition of AspNetPreCompile from C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Transform\Microsoft.Web.Publishing.AspNetCompileMerge.targets, with some of the property setting stuff near the top of it left out (because the original task will do that for us anyway.) Just take note of the ToolPath and CustomToolName values at the bottom of the (renamed) AzureAspNetCompiler element.
<PropertyGroup>
<!--Relative to solution root apparently-->
<LocalRepoDeploymentTools>.\DeploymentTools</LocalRepoDeploymentTools>
<AzureAspnetCompilerPath>$([System.IO.Path]::GetFullPath($(LocalRepoDeploymentTools)))</AzureAspnetCompilerPath>
</PropertyGroup>
<Target Name="NoReallyAspNetPreCompile" AfterTargets="AspNetPreCompile">
<AzureAspNetCompiler
PhysicalPath="$(_PreAspnetCompileMergeSingleTargetFolderFullPath)"
TargetPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)"
VirtualPath="$(_AspNetCompilerVirtualPath)"
Force="$(_AspNetCompilerForce)"
Debug="$(DebugSymbols)"
Updateable="$(EnableUpdateable)"
KeyFile="$(_AspNetCompileMergeKeyFile)"
KeyContainer="$(_AspNetCompileMergeKeyContainer)"
DelaySign="$(DelaySign)"
AllowPartiallyTrustedCallers="$(AllowPartiallyTrustedCallers)"
FixedNames="$(_AspNetCompilerFixedNames)"
Clean="$(Clean)"
MetabasePath="$(_AspNetCompilerMetabasePath)"
ToolPath="$(AzureAspnetCompilerPath)"
CustomToolName="azure_aspnet_compiler.exe"
/>
<!--
Removing APP_DATA is done here so that the output groups reflect the fact that App_data is
not present
-->
<RemoveDir Condition="'$(DeleteAppDataFolder)' == 'true' And Exists('$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data')"
Directories="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data" />
<CollectFilesinFolder Condition="'$(UseMerge)' != 'true'"
RootPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)" >
<Output TaskParameter="Result" ItemName="_AspnetCompileMergePrecompiledOutputNoMetadata" />
</CollectFilesinFolder>
<ItemGroup Condition="'$(UseMerge)' != 'true'">
<FileWrites Include="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\**"/>
</ItemGroup>
With this in place, everything works as I would expect it to.
I tried every solution i found in the internet.
Im using flex 4.5, This is what im doing:
created directory locale/en_US in my src directory
add resources.properties file to that directory with some mappings.
add -locale en_US -source-path=./locale/{locale} -allow-source-path-overlap=true to the compile args.
checked in the framework that the en_US locale directory appear.
add metadata:
<fx:Metadata>
[ResourceBundle("resources")]
</fx:Metadata>
starting the app gives me the exception:
Error: Could not find compiled resource bundle 'resources' for locale 'en_US'.
This is some of the main solutions i tried:
uncheck "Remove unused RSLs" from the build path.
add the directory as a source path.
using the argument -include-resource-bundles and give my directory here (with using the argument -resource-bundle-list to get all bundles).
Any idea what else can i do?
Here is my structure for a mobile app (Android and iOS):
In src/locale I have 3 subdirs: de_DE, en_US, ru_RU
And in compiler options: -locale=ru_RU,en_US,de_DE -source-path=locale/{locale}
For another mobile app I have:
In src/locale 4 subdirs: en_US, hr_HR, sr_RS, sl_SI.
I had to add the latter 3 dirs with copylocale command.
And in compiler options: -locale hr_HR sr_RS sl_SI en_US -allow-source-path-overlap=true
Both apps work well for me with the latest Apache Flex SDK.
Here is the contents of a src/locale/hr_HR/recources.properties file:
# resources.properties file for locale hr_HR
navbar.tables=Stolovi za igranje:
navbar.all=Svi
navbar.vacant_long=Slobodni
navbar.vacant_short=Slb.
navbar.full_long=Su puni
navbar.full_short=Su puni
comments.good_long=dobri
comments.good_short=Dbr.
comments.bad_long=loši
comments.bad_short=loši
comments.without_long=neutralni
comments.without_short=ntr.
help.title=Pomoć
OK i found a solution here:
http://www.nbilyk.com/flex-localization-example
im really not sure why it should be that difficult.
anyway, if someone ever need a help with that. after you successfully compile the file using ant (like described in the link), if you want to load it dynamcally like i needed just use (for example):
resourceManager.localeChain = ["en_US", "es_ES"];
resourceManager.loadResourceModule("Resources_en_US.swf");
resourceManager.loadResourceModule("Resources_es_ES.swf");
worked well for me, no need to add anything to the compiler args for that solution.
Try using the fully qualified directory path name. If you're using ant you can use ${basedir}/src/locale/{locale}