|
Hi, firstly I think this tip is useful, thanks!
But in the passage or downloaded solution, I only see very simple library times, which contain only 1 cs file. What if the library contains many other file types, such as Xaml, Resources, and so on? Do we have to add the types in merged csproj file? Could you have a try and update the source code?
|
|
|
|
|
Thank you for the comment, I'm glad you liked it.
Now regarding the rest of the files, well this will depend on the way the files are included.
If you right click any file and select "Properties" then in the "Properties" dialog under the "Build Action" you can find this information.
For the CS files it will be "Compile" and for some other files (for example XML files) it can be "Content" and for them you could use something like the following:
<Content Include="..\MyLibrary1\**\*.xml">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<Visible>false</Visible>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Regarding the "Resources", honestly I don't remember exactly why but I decided to use "Pre-build" event for transferring both "Resources" and missing "References" (I just remember that I was stuck on some issue and was very short on time so the fastest resolution was avoiding the issue with a script).
Nevertheless I appreciate your suggestion and I'll try to add some complexity to the projects content when I find the time for it.
|
|
|
|
|
Thank you for quick response!
Do I have to replace
%(RecursiveDir)%(Filename)%(Extension)
with those actual names in my project? Also, from your reply of *.xml I think much manual effort will need to handle many file types and special situations.
How about build a tool to automate this? Is it possible?
modified 10-Dec-15 3:59am.
|
|
|
|
|
Regarding the first question, note that %(RecursiveDir) , %(Filename) and %(Extension) represent any Item's Metadata information that is available to you in MS Build via those variables. The full list can be found here[^].
So in short this will result in giving the same name (and its relative path) to the Item that is included.
Regarding the second question, that was just for a demonstration purposes but I believe that you could achieve the solution that would handle many file types. At the top of my head what I would try is to use a the following Include statement Include="..\MyLibrary1\**\*.*" and I would additionally Exclude the extensions that are not included in the project as "Content" (like CS).
|
|
|
|
|
Even though this technique may seem interesting, this is not the same as merging assemblies.
The purpose of merging assemblies is questionable. But at least the result is elimination of the overheads of all separate assemblies except one, the overheads of all separate executable modules except one, which gives the resulting form of the product lighter weight, compared with the original set of assemblies.
Your technique does the opposite: without removing any overheads, you add some overhead for organization and using resource. Isn't it obvious? So, if you technique has some benefits, you should have discussed them in the article. Could you?
Thank you.
—SASergey A Kryukov
|
|
|
|
|
Thank you for comment, unfortunately I did not understand you completely.
Could you please elaborate a bit the following.
JSergey Alexandrovich Kryukov wrote:
... the result is elimination of the overheads of all separate assemblies except one ...
Sergey Alexandrovich Kryukov wrote:
... Your technique does the opposite: without removing any overheads ...
I apologize but this seems contradictory, this approach results in single assemblies but it does not remove overhead?
Nevertheless note that in almost all situations merging assemblies really does not remove overhead, but that is beside the point, the main purpose why anyone is looking to combine multiple assemblies is to simplify the deployment (to provide a single DLL or EXE to an end user) or because of the implemented plugin mechanism of his application that requires a single file.
Now you should have realized that this is not an article but rather a tip about a very simple approach that I found to be unknown by many, as such I was not expecting a random reader that would review it as an article, but rather I was expecting a developer who is looking for the above mentioned requirements.
Also yes, this is not a solution for every situation and that is why I emphasized that a reader should consider those two bullet points at the end and decide if this suites his needs.
I used this approach in quite a few occasions, but in some cases I do avoid it.
For example when having primary and secondary assemblies each with their own resources.
The reason is because it would require additional hassling with project files and then it just loses its simplicity and in that case it's much easier to just use some external tool.
Even though this approach was of help to few developers (you see that is one of the reasons why I published this, so I can just send a how to link in future ), you are entitled to your opinion, but I would lie if I were to say that it's a valid reason for your downvote...
|
|
|
|
|
I apologize in case I misunderstood your technique or the results. We can continue this discussion later, in order to get to the truth; you will be able to correct my mistakes.
But first, I think you have to understand that assembly merge removes overhead. I just never said the overhead is considerable; I discuss the principles. Merge N assemblies in one. You had N assembly manifests, end up with one. Now, each assembly has one or more executable modules. Each module is the overhead in PE file, and in memory, because reflection requires accessibility of all header module metadata. You had M module (equal or more than N), end up with one. Small or big, but you are getting rid from some overhead.
The simplification of development, I think, is nearly fictional. How cares how many assemblies are there in the API?
—SASergey A Kryukov
|
|
|
|
|
Yes I do understand your point regarding the overhead removal, but I just wanted to point out that it's an absurd idea that this is a meaningful benefit of merging. I mean even you agree that it is an insignificant overhead... you must realize that no one is looking for a solution to merge its assemblies due to this reason.
I really apologize if I'm wrong here, but I believe you have never encountered a situation in which you had to merge multiple assemblies. And if that is true then I don't understand why would you downvote something that you never had to use, because you don't see its usage?
I feel that this was very rude from you, I mean if it was an article I would understand but downvoting a tip because you don't see its usage...
You see this is a simple alternative for combining multiple assemblies that does not require any tool and this tip specifically targets the developers in search of assembly merging solution:
Mario Z wrote:
Whoever searched for a solution to merge multiple assemblies into a single file ...
Also I presume this is probably your typo, but the simplification is in the deployment, not the development.
Sergey Alexandrovich Kryukov wrote:
The simplification of development, I think, is nearly fictional.
Nevertheless believe me when I say that every developer (or at least a large number of them) that is working in component vendor company will strongly disagree with you.
Also I truly thing that every developer that offers any sort of library will disagree with you as well.
There really are quite a few use cases that require a single file, to name a few that I encountered: portable applications, pluggable applications, CI simplification (the above approach is ideal for this because it removes the dependency with merging tool).
Conclusion that I'm trying to make is that one does not decide to merge assemblies, he only looks for the solution to it when it is needed.
If you do not have this requirement then there is no point in doing this.
Also my goal here was to provide a resource about an approach that I was learned how to achieve, this approach can be found on few forums as a suggestion, but I was never able to find any document that describes it. So I decided to provide a brief explanation on how to exactly do this.
I always thought of CP as a great resource place and I would thought that a long time CP writer like yourself would appreciate the information that is provided to everyone and not judge it based on his needs.
|
|
|
|
|
All right, I really try to understand who is right here and what is your contribution. But first, we need to agree on one thing: you should not try to press on anyone discussing the votes on any posts. Formally, you cannot even know who is voted, you only have the general statistics. And I don't want to discuss it, to avoid creation of the precedent. This is a free community where we freely express our opinions and people are not used to arguments over votes. We all, including myself, receive our share of bad voted, and some can be unfair. You need to earn votes by our posts, quality of content. You should not blame anyone for being rude just for posting. Who told you anything rude? If you continue such arguments, I'll have to stop the communications.
I already give you my arguments on your article value, so, if you want, we can discuss it. I can vote any time the way I find appropriate, but of course, we can argue over my opinions.
So, here is another thing: look at the article you quoted first. It comes with source code. Anyone can download it and try out. What can you present to anyone so this person could quickly perform the build and then look at the results, do some tests, anything. It needs comprehensive solution with one-click build. Without it, the article on this topic could not be considered good enough. You really need to provide such a way for the reader.
Now, after some more reading, I can say that I really don't quite understand your approach. But it means that I need some more detailed information. It's quite possible that I misunderstood you. I still think that not seeing the usage would be not only my fault; if you claim something, you have to explain the value.
You are quite right that I "never encountered a situation in which you had to merge multiple assemblies". So what? Do you have any rational arguments. Your arguments on my consideration on overhead miss the logic. The saving overhead is pointless, is that what you say? All right, I would not disagree, I only say that usual merge save on them. I never advocated importance of it. I just thought that this is at least some benefit and speculated that your approach does not offer it. But now I probably can see that your solutions removes the overhead as well. All right, if this is not a point, there is no a point to argue.
Now, let me understand if there is another thing: maintenance overhead. How would you support modified solution for "Release"? Are you still able to add new projects to the solution, move parts of code from one project to another one, in few words, do all multi-project engineering freely? I see the problem here. If this is all possible and well maintained, please explain. Again, without a comprehensive code sample, it's hard to do.
Your arguments based solely on the assumption that the merge is useful itself, the value is having one file instead of few, and your only argument is "that every developer (or at least a large number of them) that is working in component vendor company will strongly disagree with you". How, how can you know what "every developer" thinks about it? Please, let's discuss only rational arguments: why you think that having just one file worth the effort.
Thank you for understanding. I really hope you update the article, provide a comprehensive sample and rational arguments.
—SASergey A Kryukov
|
|
|
|
|
Yes I must admit I got a bit upset for bad vote, it's just you are my first downvoter (probably not the last ). Also I apologize for calling you rude, I should not have done that and you are absolutely right, this is a free community and I shouldn't have imposed myself.
Now back to a discussion, first regarding the source code, I really thought there was no need for it here.
The image shows the resulting combined assembly and snippet codes provide all the necessary changes that need to be made to accomplish it.
What I was thinking is if this solution suites someone then he would try it out on his solution, it would literally take just few minutes, after all that is probably the reason why he was searching for this topic.
Nevertheless I will take your advice and provide a source code.
I must admit that it seems to me that you have the same criteria for an article and tip/trick posts. Note that CP Submission Guidelines states:
"Tips n tricks are meant to be very, very short tips, snippets or even just a one-liner you came across that saved your day. Articles are for presenting more detailed ideas."
Again please understand that this is tip/trick and I was trying to keep it simple as much as possible.
"Are you still able to add new projects to the solution, move parts of code from one project to another one?"
You can freely move parts of the project, but regarding the new projects you can add it but without adjusting the project's file with the above approach that newly added project will be built as a separate assembly.
"How, how can you know what "every developer" thinks about it?"
It may seem as an exaggeration, it probably is a bit, but I'm pretty sure about component developers because I work at a component vendor company and I'm familiar with work of few others.
But in short you can just take a look at couple of components and see that the opinion is mutual on this matter.
"Your arguments based solely on the assumption that the merge is useful itself, the value is having one file instead of few, and your only argument is "...
I'm not sure why you are ignoring the few use cases that I already mentioned (portable applications, pluggable applications, CI simplification), these where not my use cases but I do remember them.
Nevertheless one of my use cases, when you are providing a usable component you want to simplify a specific task to developers. So keeping in mind that your goal is to ease other developers task doesn't it feel only natural to make the component available to other developers in most simplest manner possible, I believe you will agree that there is no simpler way then adding a single file and its reference.
If some user has difficulties in adding your solution into a project he will just give up.
Also there are no benefit of having multiple files (your solution is still separated in the organized projects), you are just making other developers job harder.
Now yes this does not reflect on NuGet and setup distribution, but some developers prefer to consume the components as private assemblies.
Also the component's deployment is just simpler, it is easier to build documentation, obfuscate, create NuGet package, create setup, etc. by manipulating with one DLL rather than N DLLs.
There are probably other benefits as well, but I'm taking much for granted nowadays so unfortunately nothing else comes to my mind right now.
Again I need to point out that there are various use cases, that is why people are searching for the solutions to combine their assemblies, but this is not an article that talks about why you would want to combine your assemblies, this is a tip that demonstrates one simple way how this can be done.
|
|
|
|
|
Thank you for your understanding. We are really supporting civilized and respectful dialog. I think your approach deserves attention and respect your work, but I want to make it more clear to myself, first of all.
I don't have much time now, let me first respond to the part of your post. I authored Tips/Tricks article without source code and with it, for most recent one. The criteria is not the size, but importance of the technique and with width of the scope. In both kinds of articles clarity is expected. As typical Tips/Tricks article discusses just one aspect or particular technique, all the comprehensive code can be placed on the single page. But still, it has to be comprehensive, for example, one single class with clear ins and outs.
Why it can be quickly built? A reader can copy and paste it in some rudimentary project (say, created from template) and compile immediately. If many related fragments of code are involved, it's hard to do unless the whole ready-to-built solution(s) is(are) provided. It was your decision to publish your article as Tips/Trick, but you still need to provide easy way to use your code immediately. In your case, a fragment does not allow one to quickly copy-paste it and see the result immediately. I think, this is obvious. Therefore, we come to the need of the whole solution, which requires at least few files in integrity. I hope you'll find this conclusion logical. Posting of a ZIP with a Tips/Tricks article is supported, I recently checked it up.
Please reply, but I'll first have to re-read your last comment again, when I got a bit more time.
—SASergey A Kryukov
|
|
|
|
|
Thank you for the advice, I now understand what you mean.
It's true, I did not provide a result that can be observed immediately.
Unfortunately I previously did not consider that.
Also thank you for having patience with me and again I must apologize for starting off on the wrong foot.
|
|
|
|
|
Please don't apologize anymore; we are perfectly good, I hope.
I still hope you will elaborate the approach you started to explain in this article. Will you add the code and more detail to it?
If you are not sure, I can ask you some questions I may have, but if I can wait until you update the article, I'll rather wait. Please respond, what would be better for you.
As to the votes… As far as I can see, it looks like you are knowledgeable and qualified enough, so good voted won't miss you, including those from myself, and maybe on the present article, too, but right not it needs improvements.
—SASergey A Kryukov
|
|
|
|
|
Currently I just added a small solution for downloading, but yes I also intend to add some improvements as well when I find a time for it, hopefully this weekend.
Regarding the votes, however this may sound strange to you I must admit that your downvote was of great value to me and I'm really glad for it and for our discussion. I learned that I shouldn't take votes so personally, as you mentioned:
Sergey Alexandrovich Kryukov wrote:
We all, including myself, receive our share of bad voted, and some can be unfair.
So if I'll be hanging here on CP (which I intend to do) bad votes will occasionally happen.
Don't get me wrong, it's not that I'll stop caring what readers will think about my articles (note that I'll always appreciate any feedback), it is that I need to learn to accept constructive criticism and improve my writing skills based on it.
|
|
|
|
|
All right, thank you very much, now it's nearly all clear. And now I voted, but only with my 3 (and sorry, still not 100% sure it deserves it), which is a neutral vote, won't add or subtract any points.
Your solution is not without inventiveness and demonstrates the understanding of MSBuild, life cycle and so on. And, it finally confirms that you are actually reduce the overhead of having separate assemblies and separate modules. I actually realized that after we exchanged out first comments, because I confused your approached with the ones you referenced, but later I understood the idea more correctly. Your source code sample finally explained it all. This is good.
But as to maintainability…
First, let me show you, for comparison, my own tiny solution on project files, not related to merging, but using manual editing of the project file. It can be useful for you, too: VB.net. Bring all files over with referenced .NET dlls files when compiling. Can you see the point?
Now, as related to your approach, the point is different. Look at the development cycle: when I create a brand new project, I edit the project file and change output paths in text editor. I do it only once in a project lifetime and don' touch it any more. At the same time, I can add and remove any code files and other resources, I can even relocate the project in the file system, rename it, and only in the rare case when I modify the project location changing its depth in the directory structure, I have to add or remove some "/.." from two OutputPath properties. That's all. The project remains open to any notification.
With your solution, I've done obvious experiment: 1) added new file with new class "Clas2" with one library MyLibrary1, added one static method to the class, 2) added to the executable the call to the new method, 3) compiled in the configuration "Debug", 4) executed "MyExecutable.exe". Naturally, all worked. And, as I expected even before I asked your to add some code sample, I get compilation error with "Release": "The name 'Class2' does not exist in the current context". Of course, this is because this is how your approach works. It cannot tolerate project changes. And this is what I suspected from the very beginning, even when I did not understood 100% of how it works (some detail were not on the article page). And now what happens when you add more and more projects and more and more code files to them? I think the answer is apparent. Again, what's the use?
However, your article can be considered as a food for thought. It is obvious that the solution to automate all this could be found. Probably, you need to create a custom MSBiuld Task and organize the dependencies the way it would be built always before it is used. I've done such thing; it is a working approach. But 1) the question is: does it really worth the effort just for merging? 2) you are not yet there.
I hope my review is clear. Thank you for your understanding.
—SASergey A Kryukov
|
|
|
|
|
Yes I did get an error immediately after switching to Release mode, but did you try building it or running it anyway?
You should notice that the build succeeded and you are able to run the application, also the behaviour that I get is after I build it and waited for few seconds the error disappeared. Strange behaviour indeed, I would suspect that the VS's live error checker has some difficulties in rapidly adjusting from Debug to Release settings and vice versa.
We just need to be a bit patient with VS
In reality even if you use the same name for a class in MyLibrary1 that already exists in MyLibrary2 the imported files will not have a collision. You can also notice this by changing the included items visibility:
<Visible>true</Visible>
For example instead of naming the class Clas2 you could have named it MyClass2 and with the visibility on you would get a following structure in Solution Explorer:
MyExecutable
- ...
- MyLibrary1 folder
-- MyClass1 linked class
-- MyClass2 linked class
- MyLibrary2 folder
-- MyClass2 linked class
- Program class
- ...
So in short the approach really does not have problems with adding new code files.
However adding new project as mentioned before does require project file's adjustment, but then again every solution for combining assemblies will require some sort of an adjustment for this as well.
Nevertheless I'm aware that in some scenarios problems may occur with this approach (for example resource related), but for the most common scenarios it is simple, useful and it works.
Now regarding a custom MSBuild project file I just wanted to add that this trick can be applied in it as well. It would require to define those Include s and Exclude s in <CSFiles> and then compile those sources with <CSC> .
But honestly I personally wouldn't hassle myself with that, I use MSBuild for other purposes (mostly for defining a chain of <Target> s like running unit tests, code analysis, etc. together with projects builds) and when the above trick is not compatible with the given solution I'll rather just use ILMerge in MSBuild.
Also just as a side note, in the last bullet point I mentioned that assemblies need to be written in the same .NET language. In case someone would go for MSBuild then he could achieve combining of multiple assemblies from different .NET languages.
For example let's say you have C# class library and VB.NET class library, in that case you would compile C# sources into one .netmodule and VB.NET sources into another .netmodule . After that you would just need to use linker tool (<Exec Command="link ..." /> ) to link the C# and VB.NET modules into a single .dll output.
But nevertheless I wouldn't do that because I could achieve the same with ILMerge in less writing.
|
|
|
|
|
Perhaps you need to re-read my report. It should be apparent that I tried to build it, and it did not build, and it should not build by some pretty obvious reasons. No strange behavior at all. Perhaps you did not see the steps I did. I plan to check it up from the very beginning, and then I suspected that it should not work, because, from your article, it looked as if you did not address it.
—SASergey A Kryukov
|
|
|
|
|
It is possible that I misunderstood your steps, but please do try it again.
In case the issue remains would it be possible for you to somehow provide me your sample solution, maybe upload it temporarily somewhere, I would be interested in investigating this matter.
I don't know if I can send some sort of private message here on CodeProject to you with my email, in case there is a way you could send me your solution directly.
|
|
|
|
|
I'm sorry for bothering you, but I was just wondering were you able to reproduce the issue you previously had?
Would it be possible for you to send me a solution that demonstrates it?
|
|
|
|
|
Sorry, I removed it. It's possible to reproduce it again. All it takes is to 1) get your demo solution , 2) build it, 3) and then add a new code file with new class to one of the libraries; it should be the same kind of public class with some public member (static, for simplicity), pretty much like your existing classed; 4) it will build in "Debug"; 5) Not editing any project files, try to compile it in "Release". In general case (arbitrary location of this new code file), it won't build, because the class won't be added to the compilation of "Release" application project.
There is no a room for an attachment or something on your article page. My steps are clear, you can reproduce them.
Do relax a bit — tomorrow is the 1st of April. I would like to invite your to see my new 1 of April publication and have some fun:
Some Programming Approaches to "Neuro-Linguistic Programming".
Participation in this game in Comments and Discussions is especially encouraged.
Thank you.
—SA
Sergey A Kryukov
|
|
|
|
|
Sergey can you please do me a favour and try it again, I'm really sorry for bothering you but I followed your exact steps and was unable to reproduce your issue.
Please don't ignore what I previously mentioned:
Mario Z wrote:
Yes I did get an error immediately after switching to Release mode, but did you try building it or running it anyway?
You should notice that the build succeeded and you are able to run the application, also the behaviour that I get is after I build it and waited for few seconds the error disappeared. Strange behaviour indeed...
Sergey you must realize that I use this approach in many occasions and honestly I never encountered an issue with adding a new file. You see that is the whole point of using the wild card ("\**\*.cs") in project file, it will include all the CS files.
|
|
|
|
|
Really? I remember that you did that, but it give me reasonable doubt. I'll try again.
—SA
Sergey A Kryukov
|
|
|
|
|
Sorry, I cannot reproduce it, and your comment explains why it worked, but certainly there was a problem. Apparently, I missed something. This is my fault, so I up-vote you solution again.
And if you or anyone face the problem again, or if you understand what could it be, please do me a favor, don't forget to notify me.
—SASergey A Kryukov
|
|
|
|
|
I agree with your statement exactly! If I have the source code of the dll's I want to merge ; I can just add them to a folder in my project and build.
The point of merging is more if I have several dll's that I do not have the source for; and perhaps I either want a simple single file for an end user or I want to hide the fact that I am using company x's dll from my end user because I do not want them being 'smart' and mixing and matching versions of that dll; updating it with their own flavor of it.
|
|
|
|
|
Hi stixoffire, thank you for feedback!
Yes often the merging is performed on the third party DLLs and this approach is not suited for that.
This is a multi-projects source code combining approach that results in a single assembly.
stixoffire wrote:
I can just add them to a folder in my project and build.
Well yes of course you can and the result of this is shown in the second image of this tip.
If you were referring to adding all the classes in that project (which essentially is what this approach does but it does this on each RELEASE build) then why would you have multiple projects in the first place? I mean you made some kind of separation and then you just ignored it by copying all the files in your other project.
The point is that you can maintain the separation for development and/or maintenance, but you are able to produce a single file.
stixoffire wrote:
The point of merging is ...
There are quite a few reasons why merging is done (I listed few of them in the discussion I had with Sergey), in my experience often the requirement is the one that you have also mentioned "simple single file for an end user" and in some cases you can avoid the use of some third party merging tool with this approach.
For example in one scenario a developer was using some utility libraries which are reused and shared across the company. The development of these utility libraries are (and should continue to be) separated from the development of some custom solutions. Thus when the requirement for a simple single file was introduced the straightforward solution to this was the combining approach.
|
|
|
|
|