• Advertisement
Sign in to follow this  

Different output lib file based on #define

This topic is 1654 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

I'm using Visual Studio 2012 to compile my engine/game framework to a static lib file. I support different APIs, like DX9 and DX11. Those are choosen via a #define. Only problem is, whenever switching between those two, my whole libary has to be recompiled. Is there any way to ouptut to differnent lib files, say. Engine9.lib if API_DX9 is defined, and Engine11.lib if API_DX11 is defined?

Share this post


Link to post
Share on other sites
Advertisement

Ah, that seems like the way to it. Now I only have one tiny problem left. So I made 4 different configurations: DebugX9, DebugX11, ReleaseX9, ReleaseX11. As for now, every single build outputs the libary to another directory. I tried changing the directory in the settings page for every configuration from "$(SolutionDir)$(Configuration)\" to "$(SolutionDir)Debug\" or "$(SolutionDir)Release\", however when applying the settings, it will always reverse my changes. Do I have to do this differently, or do you have any idea whats wrong here?

Share this post


Link to post
Share on other sites

Nope, dunno what is going on there. There is an "all configurations" drop down which may work? Have you changed the output .lib name to be different for each configuration (if they are all the same it could decide you want them in different directories? Perhaps...).

 

If all else fails use a post-build step to copy the lib where you want it.

Share this post


Link to post
Share on other sites

Never had an issue with it reverting changes. Just be sure to change the "Output Directory"/OutDir and "Target Name"/TargetName (forget the exact list applicable to .lib files, but there may be more than just the .lib itself you don't want to collide, which should by default be in therms of $(OutDir) and $(TargetName)). You could also have the configuration specify the define (C/C++ -> Preprocessor), not sure how your doing it currently without a config, assume your not editing a header before each build?

Edited by SyncViews

Share this post


Link to post
Share on other sites


Nope, dunno what is going on there. There is an "all configurations" drop down which may work? Have you changed the output .lib name to be different for each configuration (if they are all the same it could decide you want them in different directories? Perhaps...).

 

Yes, this drop down is there, but it doesn't work eigther. I have selected a different lib file, with an X9/X11 and a d if its debug, so its very strange... I'll look into it more deeply, considering the post-build step, but for now I've run into a far more delicate problem which actually causes external projects not to compile anymore.

 

So, I have a file like this:

#pragma once

#ifdef USE_API_DX9
#include "DX9\Def.h"
#else
#ifdef USE_API_DX11
#include "DX11\Def.h"
#else
#error "No api selected"
#endif
#endif

#if defined(USE_API_DX9) && defined(USE_API_DX11)
#error "Can only use one graphics API at a time."
#endif

Which selects the correct include-file for compile-time dependency of the API. Now, I used to manually define the USE_API_XXX at the top of this file before, which worked fine. Now I've included it under C++/Preprocessor/Preprocessor definitions, depending on the selected build configuration. Now all I have to do is e.g. USE_API_DX11 at the top of my main-file, and it selected the correct api:

#define USE_API_DX9

#include "Engine.h"
#include "MainState.h"

// Windows main-Funktion
int WINAPI WinMain(HINSTANCE hInstance,      // Handle der Programminstanz
                   HINSTANCE hPrevInstance,  // Handle der letzten Instanz
                   LPSTR lpCmdLine,          // Kommandozeile
                   int nCmdShow)             // Art wie das Fenster angezeigt werden soll
{

	AclEngine engine(hInstance);

	engine.Run<acl::MainState>();

	return 0;
}

Strangely enough, this only works for projects in the same solution as the libary. For any other project, that is part of a seperate solution, it will fail with the first error of my ApiDef-file, as for some reason the define seems to not being carried through far enough. Exactly the same code, just a different solution, and it isn't working. Any idea how to solve that?

Share this post


Link to post
Share on other sites

You can probably do that with property sheets? I don't normally deal with those so I'm not sure.

 

Things get a bit awkward if you use multiple solution files, it is much easier to use one solution and have lots of projects in the solution, if you can.

Share this post


Link to post
Share on other sites


Things get a bit awkward if you use multiple solution files, it is much easier to use one solution and have lots of projects in the solution, if you can.

 

Well, since I'm creating an engine that might be used by some people other than me; and since I want/need to have my projectes decoupled as much as possible from the engine (due to having projects in my studies not directly related to, but build using the engine); up until the point where I go unity-like without requiring to directly programm anything for a new game, I'm somewhat required to support building from different solution files. Any pointers on what options I have to make this possible (using defines across multiple solution files, or any other possibility)?

Share this post


Link to post
Share on other sites

All the engines I have used have been in-house (and for consoles not PC), so I dunno.

 

You could set environment variables perhaps, if your settings change rarely. Are users going to build against different versions of the DirectX API? If not, environment variables could be the way to go.

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites


You could set environment variables perhaps, if your settings change rarely. Are users going to build against different versions of the DirectX API? If not, environment variables could be the way to go.

 

Yes, the engine is intentended to be used in games build against different versions of the DX-API, it pretty much allows a game to run on different APIs just by changing a compile time switch. So I don't think an environment variable would be sutable here (though I might want to check them out for making the setup of a new project easier, using them for the engines include path). Any other suggestions what I might use instead? Just a quick note, it's funny though, isn't the compiler supposed to more or less just stick the header files together, so I don't really see where the big difference in preprocessor defines in eigther the same or another solution comes from...?

Share this post


Link to post
Share on other sites

If you put the macro in the project configuration C++->Preprocessor, changing the macro will cause your whole project being recompiled.

You may think to put the macro to a header file, thus changing it will cause only the files that including that header being recompiled.

 

However, I do think you need a separate build configuration rather than using a macro.

Share this post


Link to post
Share on other sites


You may think to put the macro to a header file, thus changing it will cause only the files that including that header being recompiled.

 

That was my first intention, but how do I have this macro beeing changed when I selected a different build configuration? I thought that whats the preprocessor-configuration option was for...

 


However, I do think you need a separate build configuration rather than using a macro.

 

Pretty much the same question as above: Even if I have a seperate build configuration, how would the correct API being choosen from the header files of the engine? On which API I use depends e.g. many typedefs for my interfaces, determining which type of low-level texture, mesh, etc.. wrapper is being used. With what you said first, is what I want to achieve even possible? I want to compile my engine into different libary files, and then in the project pick that correct implementation, which however does change how header files are laid out... does that even work with recompiling the engine?

Share this post


Link to post
Share on other sites

If you use seperate build configuration, it's fine to put the macros in build configuration (C++->Preprocessor) because you don't need to change the macros any more.

 

Your current approach, single build configuration, to make for DX9, define API_DX9 in build configuration, to make for DX11, change API_DX9 to API_DX11, whole project will be recompiled.

 

The seperate build configuration approach. You have two build configuration. config9 and config11. In config9, you define API_DX9 in build configuration, in config11, you define API_DX11. Now to build different target, you just select different build configuration, no need to change the macro, so only part of the project will be recompiled.

Share this post


Link to post
Share on other sites

The seperate build configuration approach. You have two build configuration. config9 and config11. In config9, you define API_DX9 in build configuration, in config11, you define API_DX11. Now to build different target, you just select different build configuration, no need to change the macro, so only part of the project will be recompiled.
 

 

I am already aware of that. If I didn't get it clear before, thats what I'm already doing. The problem is, that it won't work for a project outside of the solution the engine is in, whether I select a seperate configuration or manually define the macro. If I define e.g. USE_API_DX11 in the main.cpp-file of an app that uses the engine , it will work for a project that is inside the same solution as the engine. Any other project however, in a seperate solution, the so defined macro (whether macro or build config) won't be seen by the engine. And I do need to have the correct macro defined outside of the engine for the correct headers and interface implementations to be selected. Any ideas how to solve this?

Edited by Juliean

Share this post


Link to post
Share on other sites

Then the project that uses your engine has to define the macro in build configuration, or define the macro before include any headers in your engine. There is no better choice, IMHO.

 

There are two approaches to possible improve this,

1, Auto detect which DX version to use, if there is any version related macro in DX headers, maybe you can use it? I'm not sure if it's possible because I never used DX.

2, Change the headers in your engine DX agnostic. Thus your engine only exposes one single interface to the users. This is better API design and how a lot of cross platform open source projects do.

Share this post


Link to post
Share on other sites


Then the project that uses your engine has to define the macro in build configuration, or define the macro before include any headers in your engine. There is no better choice, IMHO.

 

Unfortunately, thats exactly what already happend. But as I described, no matter how I define the macro in the other project, if that project is in another solution, it won't work. Only for projects in the very same solution as the engine, defining the macro works. I still have to define the macro in the using project, but there it works, even if the main.cpp-code is 1:1 the same. Thats the odd thing, I'm pretty sure I'm theoretically doing everything right, but that little difference of where the project is, decided whether macro definition will work, or simply be ignored. :/

 


1, Auto detect which DX version to use, if there is any version related macro in DX headers, maybe you can use it? I'm not sure if it's possible because I never used DX.

 

Thats not really possible though, mainly because I'm on for a multi-api-support approach, and secondly because DX includes all three versions in pretty much the same location - the engine picks the correct header, based on the USE_API macro...

 


2, Change the headers in your engine DX agnostic. Thus your engine only exposes one single interface to the users. This is better API design and how a lot of cross platform open source projects do.

 

How is that supposed to work? Since my API-wrapper is compile-time dependand on which API to use,  I need to e.g. typedef which version of my dx-wrapper the api-agnostic gfx-layers should use:

#pragma once
#ifdef USE_API_DX11
#define ACL_API_DX11

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11d.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "D3Dcompiler.lib")
#pragma comment(lib, "dxgi.lib")

#pragma warning(disable:4005)

namespace acl
{
	namespace dx11
	{
		namespace d3d
		{
			class Device;
			class Sprite;
			class Texture;
			class VertexBuffer;
			class Effect;
			class Mesh;
			class Font;
			class DepthBuffer;
			class Line;
			class ConstantBuffer;
		}
	}

	typedef dx11::d3d::Device AclDevice; 
	typedef dx11::d3d::Sprite AclSprite;
	typedef dx11::d3d::Texture AclTexture;
	typedef dx11::d3d::DepthBuffer AclDepth;
	typedef dx11::d3d::VertexBuffer AclVertexBuffer;
    typedef dx11::d3d::Effect AclEffect;
    typedef dx11::d3d::Mesh AclMesh;
    typedef dx11::d3d::Font AclFont;
	typedef dx11::d3d::Line AclLine;
	typedef dx11::d3d::ConstantBuffer AclCbuffer;

}

#endif

How am I supposed to get that away from the headers, without using an interface for that low level classes (would affect performance in my render queues in a bad way, plus possibly violate multiple SOLID rules...)?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement