|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic |
Last Thread Next Thread ![]() |
| Making Your Libraries Release-Friendly |
|
![]() Anonymous Poster |
||||
|
||||
| Hello Interesting article but I think you missed out a couple of useful facts. * Try not to put paths into the Directories option in VC++. Instead there is a per build setting option in Project Settings, C/C++, Additional Includes. There is also one for libs under link. This way if Useful comes with a lib\debug\useful.lib and a lib\release\useful.lib you can just link in useful.lib and path to the correct one. This becomes invaluable when doing cross platform. Imagine having debug/release libs of a bunch of xbox, pc, gamecube and ps2. #pragma comment (lib, x) won't work on gamecube or ps2 (as far as I know), even if it did you would have a mess of pragmas for just 1 library, now think about if there were 12 libs. * Make your includes and libs, where possible, relative paths. If you have your game in a folder called game, have Useful at the same level. This way your path to it would be ..\useful\lib\release\. This works for all so long as they have Game and Useful at the same level. * If the above isn't an option consider your team subst'ing drives. We subst a drive 'R' to the Renderware install and a drive 'H' to the havok install. This lets people install them to wherever they want without breaking project settings. You can then just path to 'R:\include' for the Renderware includes. Anyway, that's just my preferences. Hopefully the article will get people thinking think a little more when it comes to distributing their libs. Thanks scott |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
Hi Scottquote: AFAIK, VC++/VSNet requires you to specify full path to the library folder in the Project settings. This is precisely what is I want to avoid. Consider this situation. I work with a programmer on the net. We both use a 3rd party library called "Useful". I install Useful library in "C:\Library\Useful". The other programmer installs it in "C:\Program Files\Useful" I hardcode C:\Library\Useful\lib in the project settings. When I pass the project to the other fellow, he has to modify the project settings before he can link. Ditto when he passes to me. quote: I never worked with those compilers but if they don't have similar functionality, then we have to specify the path expliclity on the command linker, which brings us back to square one. If there are 12 versions, so be it. It's better to rename them differently. This is to prevent linking the wrong dlls libraries and using the wrong dll because they use the same name (assuming implicit dll loading, not via LoadLibrary). We already have dll version hell, now if they are named the same, we have dll version + naming hell. quote: I personally avoid backtracking (i.e ../../) because it's hard to follow I usually add a "." in the Additional Include folder and follow it down, without backtracking. Your solutions are good, but they assume the team agreeing on a certain workflow format. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| > AFAIK, VC++/VSNet requires you to specify full path > to the library folder in the Project settings. LIBS: $(HOMEDIR)/Useful/lib/$(ConfigurationName) EXECS: $(HOMEDIR)/Useful/bin/$(ConfigurationName)/$(ProjectName).dll Plug those straight into the Properties page of your app and you're in business. Replace HOMEDIR with any environment variable you see fit. |
||||
|
||||
![]() rsegal Member since: 12/18/2000 From: Toronto, Canada |
||||
|
|
||||
quote: Sounds interesting but where exactly do you input this information. I don't see any "Properties" for project settings. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| Right-click a project in the Solution Explorer and select the Properties item at the end. In the dialog box that appears, make sure you select the All Configuration item in the dropdown box. Select Linker in the list of Configuration Properties. Select the General sub-tab within the Linker. In the right, enter the string "$(HOMEDIR)/Useful/bin/$(ConfigurationName)/$(ProjectName).dll" in the OutputFile line. Then enter "$(HOMEDIR)/Useful/lib/$(ConfigurationName)" in the Additional Library Directories line. The reason why this works is that VC++ executes the compiler and the linker in a shell which expands environment variables. NMAKE does the same thing, making it feasible to remove all absolute paths from source and build files and even introduce configuration-specific elements. What Void suggests is to introduce build commands within the source file rather than separate the build process from actual code. Once that mistake is made, there is no way you can introduce new configuration settings without touching the sources; for example, introducing a debug-profiling and retail-profiling variants can't be done without changing source code. The problem is acerbated when the same source files are used across multiple products (say - a custom math library) for which linker requirements are different and/or in conjunction with other 3rd party libraries that use the same subterfuge. The DLL Name Hell problem is replaced with a #if/#elseif/#else/#endif hell. My recommendation is to cleanly separate build scripts from the source files. |
||||
|
||||
![]() fardin Member since: 7/10/2003 From: Singapore |
||||
|
|
||||
| We started using environment variables on our previous project, but it went out of hand because of a lack of planning. But in the current one, it works pretty fine. But one question I would have for you guys, is how do you organise your project solution, source, libs, dlls, etc... and what about external libraries ? Well, obviously there are more than one way of doing the right thing, but this discussion almost triggered a holy war in the office as pretty much everyone had their own ideas about how to go about it What we are using is a project name folder, for example PROJ, and define an environment variable for it. Under that folder, we have bin, demos ( shows how various modules work ), libs, dlls, src, extern ( external libs used for that project ), proj ( only contains the VC solution that in turns includes all the other modules project files ). Under src, we have self-contained modules ( .cpp, .h, .vcproj, and a readme for each module ). Each of the modules contain a tmp folder that is the intermediary directory. Debug libs are postfixed with a "d" whereas release ones just have the name of the module itself. To make sure noone screws up, we have this "Build Nazi" dude. If someone ever does, he just sits one them! And yea... he's big! =) |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| > But one question I would have for you guys, is how do you > organise your project solution, source, libs, dlls, etc... > and what about external libraries ? As you pointed out, there are no right or wrong answers here and it depends on what product you are building and a lot about team consensus. Where I worked, the main product had around 11 million lines of code. Granted, there was a large amount of comments in there, but even at a 1:1 comment/code ratio that's a pretty huge code base to handle. The product was composed of 92 libraries, 8 of which were developped externally. The product was declined in SGI/Linux/Win32 flavors and in the Debug/Retail/Profiling compilations and in Retail/Demo versions for a total of 18 permutations. We used RCS to align all the libraries under the main product directory and used hard links for libraries that were duplicated across products. We didn't use TMP or such directories because there was one build machine per compilation configuration and it pulled the sources on the local hard disk before starting the build process. Also, we didn't make any difference between external and internal libraries; those that came compiled were inserted in the RCS tree and version-stamped. The libraries were compiled first in .lib/.a files and a final makefile would build the various executables that made up the product. There was a final phase that grabbed executables along with various assets and made the CD images; libraries and header files were 'exported' into a package any developper would pull in for the day's work. Then smoke tests were performed using the product's internal scripting ability, and then QA would perform ad-hoc and regression testing to determine if the build 'passes'. > To make sure noone screws up, we have this "Build Nazi" dude. As you can imagine, coordinating a big team around this product was essential; and we wanted to have a full product compiled each night and ready for use the next morning. We used the concept of a "build breaker" where the ones who screwed up were responsible for ensuring that compilations were fixed and restarted, then coordinate QA in testing the product; that usually took the entire day, thus introducing a negative feedback loop in the product development cycle for those loose guns in the team. After 5 build breaks within a period of 3 months, salaries/options/bonuses were revised downward. I guess we didn't have someone 'big enough' in the team... but it worked. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: This is assuming you have Useful library inside a folder of the project workspace. What if it is in a outside location. Very simple example, say I use another STL library like STLport. I don't put STLport inside every project, yet I use it a lot in other projects. quote: I think you are mistaken. The library can be specified on the project settings tabs (i.e build script), there is no need to be specified inside the source file using #pragma. My article is arguing that using the same name for different versions (ie debug/release/PC/Xbox) of the library causes more problem. Separating them by folder means the developer has to hardcode the library path in the build process. Which is fine if every developer is working using the same build environment, but not the case if the programmers are not in the same room. quote: I concur. My article goes a step furthur and suggest we do not hardcode library paths in the build script. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: My organization is I do not put external libraries inside the project. The libraries I use are like STLport, Boost etc, those which are failrly generic and frequently updated. I put all external libraries in location (C:\Library). If I update the library, I changed it here and all projects that get recompiled will use this new library. For dlls by external libraries, I put them in another folder (C:\Redist). Again I can change them to the latest version easily. One thing I would do different from you is to use only 1 intermediate output directory, instead of a tmp inside every folder. Filese in the project should be unique, and therefore their intermediate files (i.e .obj, .a, .lib) should be unique too. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
| > This is assuming you have Useful library inside a folder > of the project workspace. Environment variables makes no such assumption; paths can be absolute or relative. $(USEFUL) could point where the library is currently located and be inserted in any project settings path. Just plug "$(USEFUL)/include" in the 'Additional Include Directories' tab and "$USEFUL)/lib" in the 'Additional Library Directories' tab. It's a very powerful tool that's under-utilized. > My article is arguing that using the same name {...} Your article makes a very good point about library naming and directory conventions; I don't dispute that. But that your article's solution goes through a Microsoft-specific extension to #pragma is what made me shudder (i.e. "==> Note how this solves **all** the linking problem. <== In our code, we can do this to link Useful:" ...). > The library can be specified on the project settings tabs > (i.e build script), there is no need to be specified inside > the source file using #pragma. That was my point all along. I see we are more in agreement than in disagreement now. |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
While interesting points, none of them stop the integration of your library with a program that needs to use it. Seeming as you mention you're interested in large scale integration you should have mentioned that putting your header files in the "global" include path is just asking for trouble. You need to be including like <Useful/MyHeader.h> so your include path should be:
<Useful Project Directory>
|
+-<Include> <-- point include path to here
|
+-<Useful>
|
+- All headers in here...
I've had cases where I've been unable to use combinations of libraries because they place header files in the global path with names that clash. Not a pretty experience. This becomes more important with very large scale projects where the use of an equivalent "AllMyLibrary.h" is unacceptable; where you have literally hundreds of header files that your client will selectively include and where the chance of a name clash is greatly increased. It's like the notion of C++ namespaces, but extended to physical design. |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: My bad. I didn't see the part about environment variables. I don't use env variables like this because there are already too much env variables in my system. But it's a viable solution too. quote: Perhaps I should have worded it differently but I did say it was VC++ oriented |
||||
|
||||
![]() Void Member since: 9/12/1999 From: Singapore |
||||
|
|
||||
quote: This is a good point. If you see libraries like boost, there is a boost folder where all the headers are inside so when we call it, we call it using #include <boost/shared_ptr.hpp> Libraries should package their headers like this, in case another library has shared_ptr.hpp too. I will add these new points into the article. Thanks. |
||||
|
||||
All times are ET (US)![]() |
Last Thread Next Thread ![]() |
|