How can I exclude unnecessary DLLs from my build? - optimization

I'm trying to optimize the file size of my game, in particular the android build. I have optimized the assets and set the build stripping level to Use micro mscorlib. However, looking at the Editor.log reveals the DLLs still take up more than 50%:
Textures 2.7 mb 35.7%
Meshes 80.5 kb 1.0%
Animations 0.0 kb 0.0%
Sounds 0.8 kb 0.0%
Shaders 98.2 kb 1.3%
Other Assets 177.9 kb 2.3%
Levels 110.0 kb 1.4%
Scripts 447.4 kb 5.8%
Included DLLs 3.9 mb 52.2%
File headers 26.2 kb 0.3%
Complete size 7.5 mb 100.0%
3.9mb seemed a bit much, so I looked at which DLLs are actually added. I found this:
Mono dependencies included in the build
Dependency assembly - Mono.Security.dll
Dependency assembly - System.Core.dll
Dependency assembly - System.dll
Dependency assembly - mscorlib.dll
Dependency assembly - UnityEngine.UI.dll
Dependency assembly - UnityEngine.Networking.dll
Dependency assembly - UnityEngine.Analytics.dll
Dependency assembly - Assembly-CSharp.dll
Dependency assembly - Assembly-UnityScript-firstpass.dll
Dependency assembly - Assembly-UnityScript.dll
This looks like it can be improved quite a bit. I don't use UnitScript, so Assembly-UnityScript-firstpass.dll and Assembly-UnityScript.dll should be obsolete. Neither do I use Networking or Analytics, so these could be removed as well. Not sure what Mono.Security.dll does or whether UnityEngine.UI.dll is really necessarry.
So, knowing this, how can I get rid of these seemingly unnecessary DLLs?

There is another way of doing this:
Step 1: Right-click on the .apk file and Open it with WinRAR/ZIP
Step 2: Enter the assets folder, then enter bin\Data\Managed
Step 3: There you will find all the DLLs, just remove what you want (not that much :D)

Seems like there is not a direct way to do that. I just tried removing some dlls references on a test project and wasn't enough. Unity was including some of the removed libraries in the build anyway.
But, what if we make impossible to unity to find those elements? That approach worked.
Steps:
Remove references in Assembly-CSharp and Assembly-CSharp-firstpass
Follow the path and rename those removed dlls to something else, like filename.dd_old:
3.- Compile, Build, and see the results :)
Before:
Mono dependencies included in the build
Dependency assembly .....
Dependency assembly - UnityEngine.UI.dll
Dependency assembly - UnityEngine.Networking.dll
Dependency assembly - UnityEngine.SpatialTracking.dll
Dependency assembly .....
After:
Mono dependencies included in the build
Dependency assembly .....
Dependency assembly - UnityEngine.UI.dll
Dependency assembly - UnityEngine.SpatialTracking.dll
Dependency assembly .....
Test your game, I really don't know what can be wrong with this practice, and I mean, I really don't know what cannot go wrong with this practice :D
Rename the _old files to their original names for the next project, etc..

The Unity provides a feature to strip unused code, and therefore the dll, for you.
Follow the steps below:
Select the menu Edit->Project Settings.
In the Project Settings dialog box, select Player.
In the Player select Other Settings.
Scroll down until the Optimization section.
Change the option Managed Striping Level in the dropdown list.
This feature has many options and you can even link the specific assemblies using a link.xml file in the Assets folder.
I strongly suggest to read the Unity official documentation Managed Code Stripping for further information.
That's it. Hope it helps.

Related

Reference a csproj from same solution as xproj

I have a solution with the following projects:
MySolution.sln
- MySolution.Client.csproj
- MySolution.Service.csproj
- MySolution.Models.csproj
- MySolution.Server.xproj
MySolution.Models is a simple class library which contains shared code that is referenced by MySolution.Client and MySolution.Service - and I would like to reference it in MySolution.Server.
The GUI in VS 2015 RC1 lets me add the reference by right clicking References -> Add Reference. I then see all my projects under Projects -> Solution.
I select MySolution.Models and click Ok, after which I receive the following error in the output log:
Errors in ...PathToSolution\MySolution.Server\project.json
Unable to locate MySolution.Models >= 1.0.0-*
It really feels like this should work, since the GUI allows me to add the reference without any hiccups.
So the first thing to understand is DNX projects have no understanding of traditional .net projects. They don't read or parse csproj files. This is done to keep them cross platform and cross IDE compatible (csproj is a distinctly windows and VS specific thing).
When you add a reference to a "legacy" (I use legacy to mean a .net 4.x csproj based project) behind the scenes the IDE will run dnu wrap but it looks like in your case something broke.
The following should be done automatically.
In solution root global.json a folder "wrap" should be added to the
projects property.
A folder off the root named "wrap" will be created if it doesn't exist.
A /wrap/project.json will be created/updated with a path to the assembly (dll).
Add a reference to the assembly and version to the referencing project's project.json file.
So first thing to check is make sure you have a "wrap" folder and wrap reference in projects property of solution.json. If you don't then likely something "broke". Try removing the reference rebuilding and adding the reference back. Check the build output window for any errors (VS is still RC so there are something error which probably should be halting that are not).
Look for a project.json in the wrap folder. It should look something like this:
{
"version": "1.0.0-*",
"frameworks": {
"net452": {
"wrappedProject": "../../LegacyClassLibrary/LegacyClassLibrary.csproj",
"bin": {
"assembly": "../../LegacyClassLibrary/obj/{configuration}/LegacyClassLibrary.dll",
"pdb": "../../LegacyClassLibrary/obj/{configuration}/LegacyClassLibrary.pdb"
}
}
}
}
Note the framework version. If there is a mismatch then it will fail resolving the dependencies. For example if your MySolution.Models targets .Net 4.6 and thus when wrapped has a dnx46 framework reference but your MySolution.Server project has a reference to dnx452 (in the project.json for MySolution.Server) then it will fail when resolving the dependency to MySolution.Models.
The you quoted could probably be improved. It means that it could not resolve the dependency due to one of the following reasons
It could not find a MySolution.Models assembly (either source code or compiled dll) based on the paths it uses (starting from projects parameter in global.json).
It found a MySolution.Models assembly (either source code or compiled) BUT it was an invalid version. Check version in Models project vs the reference in Server project.json.
It found a MySolution.Models assembly but it can't resolve framework dependencies (i.e. Models requires dnx46 but Server only targets dnx452).
In my experience the third one if the most common. For the DNX templates in VS 2015 RC the default full framework being targeted is dnx452 (or is it dnx451?). New csproj projects will be 4.6 (dnx46) by default and existing projects could be just about anything.
An alternative solution:
I have found the following alternative to result in easier dependency management. If MySolution.Models will only be used by DNX projects then just convert it to a DNX project move it into the source folder and reference it directly. It will be part of the source compilation and you gain the benefits of dynamic compilation.
If MySolution.Models will be referenced by both DNX and legacy (csproj) projects then you can create a side-by-side xproj and project.json files for Models. They will be ignored by the legacy project. In essence you have both a legacy and DNX project using the same source files. You can then just like above reference it directly. Keep in mind the folder structure if the models folder is not under /src (and it probably isn't if this was an existing project) then you will either need to move it or add a reference to the folder in global.json. That sounded more confusing that it really is. Just keep in mind for a DNX project the global.json defines the relative paths to where DNX can find source code. The DNX also can resolve dependencies by nuget or searching the GAC but that is beyond what you are trying to do.

How to create master install folder with maven

Im trying to setup maven to assemble all my build artifacts into a central distribution folder. to help with explainations, ive uploaded a sample project here
This is a simple multi-module project with 2 j2ee components, each of those has a war, and ear sub-project. If you comment out the assembly plugin in the top level pom, everything will build fine.
There is also an outputFolder which is how i want things to look when the assembling is all done. Also in the outputFolder are misc jar files that will come from other sub-projects that just build a single jar (currently we have about 20 of these application jars). Now since all the j2ee projects have the same directory structure and resulting distribution formats, I wanted to create a common assembly descriptor to be re-used across all of our j2ee components (currently theres about 15).
What I have so far does not work - in that it wont find the binary artifacts from any of the subprojects. Ive tried using moduleSet and dependencySet sections in the assembly descriptor, but those dont seem to work either, i alwasy get something like: The following patterns were never triggered in this artifact inclusion filter: 'myCompany:j2ee_A_ear:ear'
Or if I try to put an assembly descriptor in the top level project, it causes wierd dependency errors when packaging my ear files.
Ive tried to use the dependency-copy plugin, but that seems to cause more problems than it solves. Also others have said, the dependency plugin is the way to go for this. Ive tried creating packaging only projects -- a sibling of the j2ee_A and j2ee_B projects in my example, but it cant seem to find any of the modules or dependencies
So im looking for an assembly descriptor (or descriptor s) that will be:
a) reusable across any number of j2ee sub-projects
b) also support single jar files
c) copy everything to a single folder
Ideas, suggestions and examples are welcome.

A layout for maven project with a patched dependency

Suppose, I have an opensource project that depends on some library, that must be patched in order to fix some issues. How do I do that? My ideas are:
Have that library sources set up as a module, keep them in my vcs. Pros: simple. Cons: some third party sources in my repo, might slow down build process, hard to find a patched place (though can be fixed in README)
Have a module, like in 1, but keep patched source files only, compile them with orignal library jar in classpath and somehow replace *.class files in library jar on build. Pros: builds faster, easy to find patched places. Cons: hard to configure, that jar hackery is non-obvious (library jar in repository and in my project assembly would be different)
Keep patched *.class files in main/resources, and replace on packaging like in 2). Pros: almost none. Cons: binaries in vcs, hard to recompile a patched class as patch compilation is not automated.
One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".
One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".
This is what I would do (and actually what I do) for both a corporate and an opensource project. Get the sources, put them under version control in a distinct project, patch them, rebuild the patched library (and include this information in the version, something like X.Y.Z-patched), deploy it to a repository (you could use SVN for this, a la Google Code1), declare the repository in your POM and update the dependency to point on your patched version.
With this approach, you can say to your users: check out my code and run mvn install and they will just get the patched version without any extra action. This is IMHO the cleanest way (not error prone, no class path order mess, no increase of the build time, etc).
1 Lots of people are deploying their code to their hosted subversion repository (how-to in this post).
One nice solution is to create a distinct project with patched library sources, and deploy it on local/enterprise repository with -patched qualifier. But that would not fit for an opensourced project that is meant to be easily buildable by anyone who checks out its sources. Or should I just say "and also, before you build my project, please check out that stuff and run mvn install".
I'd agree with this and Pascal's answer. Some additional notes:
you may use dependency:unpack on the original artifact and then combine that with your compiled classes if you don't want to rebuild the whole dependant project
in either case, your pom.xml will need to correctly represent the dependencies of that library
you can still integrate this as part of your project's build to avoid the 'deploy to a repository' step
make sure you honour the constraints of the project's license when doing all this!

How do I fix fatal error C1113: #using failed on 'Mylib.lib'

I have a project which uses C++/CLI to implement a GUI and some background processing to talk to a sensor. I've got that all working and a lot of the comms stuff which we use to communicate the the sensor sits in a .dll. The problem is that I'd like to combine the library into the main executable to avoid having to worry about distributing .dlls.
I've got a demo project which works fine using a .lib but when I try and switch the mani code body to produce a .lib instead of .dll I get the following error:
1>------ Build started: Project: MyTool, Configuration: Debug Win32 ------
1>Compiling...
1>stdafx.cpp
1>.\stdafx.cpp : fatal error C1113: #using failed on 'c:\projects\MyTool\debug\MyLib.lib'
A bit of googling suggests this happens when you've not got the MSIL switch applied, but it's definitely in there in the library project.
I have a mixture of managed and unmanaged code in both my demo project and the real thing so I'm really struggling to see what the problem is here.
Any suggestions would be very gratefully received!
I am guessing a bit, but I suspect the "MyTool" project has the "MyLib" project as one of its "references" ("Project" menu >> Properties >> Common Properties >> References).
When you change the type of the MyLib project to a LIB instead of a DLL, you need to remove "MyLib" from the project references. You then update the project dependencies of the solution ("Project" menu >> "Project Dependencies...") so that MyTool depends on MyLib.
If you are linking to a mixed mode (managed/native) DLL you may get this error. Which you shouldn't if the project uses CLR even if one of the source files doesn't. But anyway, if that is the case, then try removing the reference from Project|Properties|Common Properties|References and then re-adding it.
I also ran into this. The reason it was failing was because I was compiling my native/managed C++ DLL to target .NET 4.0. And the DLL I was #using was a .NET 2.0 DLL. As such it was failing, even though the paths and file names lined up perfectly. In this case the error message was absolutely of no help at all.
I solve it by updating the independent DLL to .NET 4.0. So that both assemblies were using the same .NET framework.

Microsoft Assembly configuration for 32-bit mixed C/C++ application

We have a 32 bit mixed C/C++ application that we are trying to deploy to the world.
It naturally uses C and C++ runtime DLLs. We are using VS 2005.
The manifest constructed by VS2005 is the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.42" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
We ship this as a file in the same directory as the "application", named
(changed to protect the innocent) "application.exe.manifest".
On the face of it, it is sort of reasonable. But, in installing on some
systems, we get the message when "application.exe" is launched:
This application has failed to start because the application configuration is incorrect
One way to cure this is to run VCRedist_x86.exe from MSDN. (Unfortunately,
while we can run it, we don't know exactly what it is doing.
It appears to be parking DLLs in the SxS directories. But what else
does it do?)
a) The MS docs seem to indicate that the assembly must have an assemblyIdentity
tag directly underneath the assembly tag, that names the application itself.
This is clearly missing here, but the manifest seems to partially work in that
if we remove it, the application doesn't start even if the DLLs are present.
b) Remarkably the assembly doesn't mention the C runtime DLL. Do I need to just add that by hand?
c) We dont want to be dependent on whether the right version DLL is present on the target machine. Assuming that the assembly makes it clear which DLLs to use, how is that we can ensure the DLLs we need are on the target system? (In particular, we don't want run VCRedist or ask our customer to do this). Before assemblies came along, we solved this problem by simply placing the C and C++ DLLs in the same directory as the application .exe file, and Windows would look there first to pick them up. Can we still ship the C and C++ DLLs in the same directory? I can't figure out from the MS docs I can find how the SxS finds the appropriate dependent assemblies.
Any help appreciated.
a) The manifest xml validation clearly has some problems. Depending on the version of Windows this may or may not be an issue. Since so many applications don't correctly follow the schema (and because it was never properly enforced), I doubt it will ever be strict here.
b) The C runtime DLL is referenced in the Microsoft.VC80.CRT.manifest file, pulling it in to to the loader dependency graph. Providing you have a dependency on the manifest, you will also implicitly have a dependency on the DLL.
c) Per my earlier comment, the correct thing to do (aside from installing the latest redist system wide) is to put the CRT manifest and all three DLLs in your application directory. This is poorly documented under SxS: Private Assemblies and Installing Side-by-side Assemblies as Private Assemblies. The probe order is defined in Assembly Searching Sequence.
Generally a SxS binding failure will put an entry in the Application (for Vista+) or System Event Log (pre Vista) describing the error.
Activation context generation failed for "C:\TEMP\sxs\PEVerify.exe".Error in manifest or policy file "C:\TEMP\sxs\Microsoft.VC90.CRT.MANIFEST" on line 4.
Component identity found in manifest does not match the identity of the component requested.
Reference is Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a18e3b",type="win32",version="9.0.21022.8".
Definition is Microsoft.VC90.CRT,processorArchitecture="x86",publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="9.0.30729.1".
Please use sxstrace.exe for detailed diagnosis.
You can use sxstrace.exe in (Vista+) to see what the loader is actually doing. Junfeng covers this in more detail in Diagnosing SideBySide failures.
To get a better understanding of what is happening at runtime (after the manifest has been parsed and dependencies located), enable "Show Loader Snaps" for your image file (just the filename and extension, do not enter a directory name, like so: "notepad.exe") using gflags.exe. Run your application under windbg (Visual Studio's debugger may also work) and look at the output. Make sure to disable loader snaps when you're done debugging since it will slow down the application even when no debugger is attached. Sample output looks like this:
2d6c:36b4 # 1246428223 - LdrpHandleOneOldFormatImportDescriptor - INFO: DLL "C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\PEVerify.exe" imports "MSVCR90.dll"
2d6c:36b4 # 1246428223 - LdrpMapDll - INFO: Mapping static redirected DLL "C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2\MSVCR90.dll"
ModLoad: 4fbd0000 4fc73000 C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2\MSVCR90.dll
2d6c:36b4 # 1246428285 - LdrpMapDll - INFO: Mapped DLL "C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2\MSVCR90.dll" at address 4FBD0000
2d6c:36b4 # 1246428285 - LdrpHandleOneOldFormatImportDescriptor - INFO: DLL "C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_5090ab56bcba71c2\MSVCR90.dll" imports "KERNEL32.dll"
You could link the C/C++ runtime statically.
You can change the library linkage in the C/C++ compiler options in the Code Generation section. Change the entry from Multithreaded [Debug] DLL to Multithreaded [Debug].
Your DLL will then contain the required parts of the runtime, and the separate installation is not required.
I've never understood how the manifest stuff all hangs together ... but instead of placing the C runtime DLLs in the same directory as your exe try copying the whole 'Microsoft.VC90.CRT' folder from the redist folder in the Visual Studio install (C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\x86\Microsoft.VC90.CRT on my machine).
I believe Microsoft encourages the use of shared libraries and running the official redist since it installs the libraries 'properly' and means they can patch security issues that may be found in them.