Premake directive to embed a static library into a static library - visual-studio-2013

First, I'm using premake5 and VisualStudio 2013. Please don't jump on me for that one (since premake5 is still alpha). I have already searched and can't find an answer, not one that actually works.
I need to embed a static library into a custom static library using premake. I'm converting some older code after updating the libraries and only want to link the custom library with the application. I don't want to have to link the custom library and all the other libraries it deals with to the application configuration. Everything else with premake5 is working swimmingly.
I can get it to link to the application fine using the link directive, example:
links { "SDL2", "SDL2main", "SDL2_image" }
This works fine for normal inclusion of static libraries but I need a way to embed say these example libraries into a custom static library.
I can take the resulting project files that premake creates into visual studio and manually modify the project to add the libraries the way I need to, but I don't want to have to do that every time I need to regenerate the project.
The result I need is a way for premake to generate the following XML into the project xml files:
<ItemGroup>
<Library Include="..\deps\SDL2\lib\x86\SDL2.lib">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Win64|x64'">true</ExcludedFromBuild>
</Library>
<Library Include="..\deps\SDL2\lib\x86\SDL2main.lib">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Win64|x64'">true</ExcludedFromBuild>
</Library>
<Library Include="..\deps\SDL2_image\lib\x86\SDL2_image.lib" />
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Win64|x64'">true</ExcludedFromBuild>
</Library>
</ItemGroup>
This is the result of manually editing the project in visual studio. I added the exclusion of the libraries from an x64 build because ultimately, I have to use x64 versions of these libraries as well. It would be great if I have seriously overlooked something but I need to be able to get this to work.
Did I overlook something really simple here?

Premake doesn't support linking static libraries together out of the box, as that behavior isn't portable to other toolsets. However, you can install a small extension in your project script to make it work:
---
-- Allow static library projects to link in their dependencies. Visual Studio
-- doesn't support this out of the box, so I need to manually add items to
-- the list of additional dependencies.
---
local p = premake
function myAdditionalStaticDependencies(cfg)
local links = p.config.getlinks(cfg, "siblings", "fullpath")
if #links > 0 then
links = path.translate(table.concat(links, ";"))
p.x('<AdditionalDependencies>%s;%%(AdditionalDependencies)</AdditionalDependencies>', links)
end
end
p.override(p.vstudio.vc2010.elements, "lib", function(base, cfg, explicit)
local calls = base(cfg, explicit)
if cfg.kind == p.STATICLIB then
table.insert(calls, myAdditionalStaticDependencies)
end
return calls
end)

Related

Can I include an existing static library in my own static library project?

I am creating a static library project in visual studio for personal use, and I'd like to include another existing static library into my own static library.
Usually (for executible projects) I can set up extra include and lib directories in the project's properties, but this time the menues are different and I don't know which settings to use. How would I do that?
You can include a static library inside a static library, but it generally leads to bloat and other problems.
The best approach is usually to add the link library to your 'public header' using a #pragma so it's automatically linked:
#pragma comment(lib,"nameoflibIneed.lib")
I figured out a sort of hacky way to make it work.
I just included the library normally as I would in a normal project, and only after that I changed the project type to .lib.
Apparently the additional dependencies get saved after changing the type of the project even though the respective menus in the project configuration pages disappear.

Visual Studio : create a DLL that uses another DLL

I am building a DLL using visual studio, which involves installing the following libraries :
GLM
GLFW
GLEW
I linked those libraries to visual studio using the following method :
specifying Additional Include Directories in the project property page
specifying Additional Dependencies in the project property page
specifying Additional Library Directories in the project property page
Of course GLM is a header only Library, which means that I am only required to specify the Additional Include Directories for GLM. And my dll built perfectly fine.
But the real problem occurs when using the library in a test project. I linked my test project to my library using the method mentioned above, but when I tried to build the test project, it produces the following results :
Cannot open include file <GLFW/glfw3.h>
And the same goes for glew. It seems that these libraries are not found when the library is being used by another test project. How can I fix this? Any help would be highly appreciated.
Set the Additional Include Directories correctly for all projects. The compiler doesn't magically inherit settings from a project which happens to have it's output linked into another project. So you have to provide it the correct include path for any source file it sees. To spare yourself from having hardcoded paths to include directories you could use a property sheet common for both projects. Or you could tackle the problem in code and make use of the PIMPL idiom (eventually as simple as e.g. forward declaring some GL types and using a unique_ptr to them in public classes) so the headers of your project never expose any of the external include files.

C++ Making My Own Library

I have been writing my own library wrapper for Win32. I want to have it as an easily accessible library I can include in my projects.
Currently I have to manually add all the files to the project I am creating, then add the code:
#include "..etc/somefolder/frzn_windows.h"
Is there a way I can setup Microsoft Visual Studio 13 to automatically link the folder I store "frzn_windows.h" in, and also so I don't have to add each .h/.cpp file to the project. Similar to how it knows "windows.h" or < string>, etc.
I don't want the library to be a .dll or anything, just code that includes a bunch of classes to make it easier to use the Windows API.
You can use Additional Include Directories feature, that is accessible through project's Property Pages. See official Microsoft documentation here for details.

MSBuild/VS2010: How to reference "RuntimeLibrary" compiler setting in a VS2010 "Property Sheet"

I am writing a Visual Studio 2010 property sheet to integrate a complex 3rd party C++ library.
To determine what pieces of the library I need to link to my projects (as well as configuring various defines, includes, directories, etc.), my property sheet needs to determine the project's currently configured C runtime library (i.e. "MultiThreaded", "MultiThreadedDebug", "MultiThreadedDLL", or "MultiThreadedDebugDLL").
However, as a substantially similar question here on stackoverflow pointed out, this MSBuild conditional does not work:
Condition = " '$(RuntimeLibrary)' == 'MultiThreadedDLL' "
Another option was provided, but it was for a subsequent build task. I need this value before ever getting to the build.
I've also scoured Google and Microsoft's MSDN website looking for a way to get this value and have come up empty. Any ideas?
Since there was no way via MSBuild's XML to directly get the configured runtime library, I regex'ed the project file. Here is the XML PropertyGroup snippet to do this:
<PropertyGroup Label="UserMacros">
<RuntimeLibraryRegex>
<![CDATA[<ItemDefinitionGroup Condition=".*']]>$(Configuration)\|$(Platform)<![CDATA['">(?:.*\n)*?.*<RuntimeLibrary>(.*)</RuntimeLibrary>(?:.*\n)*?.*</ItemDefinitionGroup>]]>
</RuntimeLibraryRegex>
<RuntimeLibrary>
$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText($(MSBuildProjectFullPath))), $(RuntimeLibraryRegex)).Result('$1'))
</RuntimeLibrary>
</PropertyGroup>
Now the Condition statement in the question will work as-is.
Also, please note that this MSBuild property group XML does not take into account runtime library default (e.g. if the project doesn't have the runtime library set) but can be made to easily.

How to organize C source file previously compiled by GCC Make and build them into an Xcode bundle? I have a Duplicate Symbol _main Error

How to build a .bundle from source code?
This might sound like a simple problem but it has been hurdling me for a week...
Here is my problem:
I have a bunch of .c and .h files that are organized in a folder and its sub folders. The source code was written and compiled with gcc make and tested by many other make tools. The source code has some utilities and command line tools and it has more code that serve as library for those utilities and tools. It is the files that serve as libraries that I want to reuse. (By library I don't mean static library or something, I just mean that some .c and .h files in certain subfolders provide functions that can be called by some other .c files. I want to be able to call those functions, too)
Yet my problem is more complex than that: I need to build those .c and .h into a bundle to reuse it. I am not writing my application in C; I am developing in Unity and Unity can only take in .bundle files on Mac OS.
Here is my goal:
Organize the source code folder in a proper way so that I can build them into a bundle in Xcode 4.
Here is where I got stuck:
When building the project I got the following error:
Duplicate symbol _main in
/Users/zeningqu/Library/Developer/Xcode/DerivedData/ccn-cfygrtkrshubpofnfxalwimtyniq/Build/Intermediates/ccn.build/Debug/ccn.build/Objects-normal/i386/ccndsmoketest.o
and
/Users/zeningqu/Library/Developer/Xcode/DerivedData/ccn-cfygrtkrshubpofnfxalwimtyniq/Build/Intermediates/ccn.build/Debug/ccn.build/Objects-normal/i386/ccnd_main.o
for architecture i386
I can relate to this error because I can find lots of main entries in the source code. Most of them are test utilities.
Here is what I tried:
I tried removing all those utility .c files but with no luck. The error is still there. I delete and delete until some files cannot find the definition of the function they are calling. So I had to stop there.
Though I wasn't able to build a bundle I was able to build a C/C++ static library (with an .a extension). After I got the .a file I tried to put it into another Xcode project and tried to build it into a bundle. I could build a bundle in that way, but then I had problem accessing the content of the bundle. How do I call functions defined in a .a static library if that library is hidden in a bundle? I read about Apple's documentation which says:
Note: Some Xcode targets (such as shell tools and static libraries) do
not result in the creation of a bundle or package. This is normal and
there is no need to create bundles specifically for these target
types. The resulting binaries generated for those targets are intended
to be used as is.
(quoted from: https://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFBundles/AboutBundles/AboutBundles.html#//apple_ref/doc/uid/10000123i-CH100-SW1)
Here is what I thought about:
I thought about replacing all main with something like main_sth. But the source code was not written by me so I didn't want to modify it. (It just doesn't feel like a proper way of doing things to me...)
I learnt that Xcode has gcc compiler built in. So I guess if gcc can make it, so can Xcode? It's just a wild guess - I am not familiar with Xcode and gcc.
Here is a summary of my questions:
Is there a way to properly organize a pile of code previously compiled and made by gcc make so that they can be built into an Xcode bundle?
Is it meaningful to put a .a library in an Xcode project and build it into a bundle? If it is meaningful, how do I call functions defined in .a after it is built into a bundle?
Is it proper to just replace all main() entries with something else?
Alright I think I have figured out at least one solution to the problem.
The duplicate main error was caused by a bunch of main entries in my source code. When the code was compiled by gcc make, I guess the author defined a sort of compilation order so that duplicate mains won't be an issue. (If you know how to do this, please let me know. I barely know make tools.) But when I just add the entire source code folder into my Xcode project, of course Xcode would complain during linking...
As I was unwilling to modify the source code (because the source code library is not developed by me), I decided to use another strategy to walk around this problem.
If your duplicate main error was reported from your own code, you can stop reading here. But if you are like me, with a bunch of gcc compiled source code and badly need a bundle yet don't know what to do, I may be able to help.
Okay here is what I did:
I set up an empty workspace.
I built a C/C++ static library project.
Import my entire source code folder into the static library project.
Set some header search path for the static library project.
Build the static library project. (Now I have a .a library which I could link against)
I set up another project, with a bundle target.
At the bundle project -> Build Phases -> Link Binary with Libraries, add the .a library that I just built.
At the bundle project -> edit scheme -> Build, add the static library project to the scheme and move it up the list so that it is built prior to my bundle project.
Then add .h files of my library project to my bundle project as references.
After that, add a .c file in my bundle project that basically functions as a wrapper. I picked a function that I want to call in Unity, wrote a wrapper function in the new .c file, and was able to build the bundle.
After several trial and error, I was able to import the bundle into Unity and was able to call the test function from Unity.
I was really excited about this! Though it's not completed yet I think this gives me hope and I am confident I can use the source code now! And the best thing about this solution is that I don't have to modify the library code developed by others. Whenever they update their code, I just update my .a library and that's it!
Though I have listed 11 steps I still feel that there are lots of details that I missed. So here are my references:
I followed this tutorial to build my source code into a static library: http://www.ccnx.org/?post_type=incsub_wiki&p=1315
I followed this blog to link static library against my bundle code and twist build phases and search headers: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/
I followed this doc to import my bundle to Unity3D Pro as a plugin: http://unity3d.com/support/documentation/Manual/Plugins.html
I strongly recommend the second reference because that's what solved my problem!
Though the problem is almost solved there are still a few things that I haven't figured out:
I don't know if a wrapper function is at all necessary. I will try this out tomorrow and come back to update.
-- I am coming back to update: the wrapper function is NOT necessary. Just make sure you have all the headers in your bundle project and you will be able to use all the data structures and call functions defined in your headers.
I haven't used NSBundle class though I read a few docs about it. Previously I was thinking about using that class to access my .a library encapsulated in my bundle, but as I found the solution I wrote above, I didn't try the class out.
Lastly, if you have better solution, please don't hesitate to let me know!
I tried to follow the steps in the accepted answer, but had no luck. In the end, I realised step 10 needed to be modified slightly:
Create a dummy.c under (.bundle) project and the dummy.c can just be totally empty.
Remove the setting for the library you want to link inside Link Binary With Libraries
Instead use -Wl,-force_load,$(CONFIGURATION_BUILD_DIR)/libYourLib.a or -all_load to Other Linker Flags
PS: And also can use sub-project instead of workspace. and use Target Dependencies instead of Edit Scheme to achieve the same effect.

Resources