Supporting x64 and Win32 within one solution

From WxWiki
Jump to: navigation, search

Preface

The typical programmer will face a build problem to compile an application for Win32 and for x64 platforms. The .sln 's and .vcproj 's which are generated from .dsw 's and .dsp 's support only Win32. However, you can add x64 support to the project files. If you have read the description in INSTALL-MSW.txt you know that you only need to go to the 'Build' menu and choose 'Configuration Manager...' and add 'x64'. But if you now build Win32 libraries and x64 libraries you'll end up having several linker errors and a mixed set of libraries (some for Win32 and some for x64).

This problem can be solved if you edit build/msw/*.vcproj (all of them) and the file include/msvc/wx/setup.h.

Editing *.vcproj in the directory build/msw:

An alternative

Notice that instead of changing .vcproj files you may also simply build wxWidgets from the command line using nmake. Then it is enough to simply use TARGET_CPU=amd64 on nmake command line to build the 64 bit version. Of course, you still will be able to use the IDE for your own projects.

Changing them with gawk.exe

If you have gawk.exe, you can use it to make the needed changes. Go into the directory build/msw and create following two files. Than execute VC2005_MultiTargetSupport.bat if you use cmd.exe or VC2005_MultiTargetSupport.sh if you use cygwin.

VC2005_MultiTargetSupport.awk

 {
 	PlatformPath = "\\$(PlatformName)"
 	split ("vc_lib vc_dll vc_mswu vc_mswuniv vc_mswunivu vc_mswunivddll vc_mswdll vc_mswunivdll vc_msw vc_mswudll vc_mswunivudll vc_mswunivud vc_mswunivd vc_mswuddll vc_mswud vc_mswddll vc_mswd vc_mswunivuddll", wxNames)
 	for (name in wxNames)
 	{
 		while (0!=match($0, "^(.*)([^[:alnum:]_])"wxNames[name]"([^[:alnum:]_])(.*)$", text ) )
 		{
 			$0 = text[1] text[2] wxNames[name] "DONTFINDMEAGAIN" PlatformPath text[3] text[4]
 		}
 		gsub("DONTFINDMEAGAIN", "")
 	}
 	print $0
 }

VC2005_MultiTargetSupport.bat

 @echo off
 for %%I in (*.vcproj) do ren %%I %%I.old && gawk -f VC2005_MultiTargetSupport.awk %%I.old > %%I
 rem for %%I in (*.vcproj) do gawk -f wxExtender.awk %%I > %%I.new

VC2005_MultiTargetSupport.sh

 for i in *.vcproj; do
   mv $i $i.old
   gawk -f VC2005_MultiTargetSupport.awk $i.old > $i
 done

Changing them manually

If you don't have gawk.exe, prepare for half an hour of work!

Please add the string

\$(PlatformName)

after each occurence of following strings:

vc_lib 
vc_dll 
vc_mswu 
vc_mswuniv 
vc_mswunivu 
vc_mswunivddll 
vc_mswdll 
vc_mswunivdll 
vc_msw 
vc_mswudll 
vc_mswunivudll 
vc_mswunivud 
vc_mswunivd 
vc_mswuddll  
vc_mswud 
vc_mswddll 
vc_mswd 
vc_mswunivuddll

You should end up having changed the lines which begin with one of these xml names (.vcproj files are xml files):

 OutputDirectory
 IntermediateDirectory
 TypeLibraryName
 AdditionalIncludeDirectories
 PrecompiledHeaderFile
 AssemblerListingLocation
 ObjectFile
 ProgramDataBaseFileName
 AdditionalIncludeDirectories
 AdditionalDependencies
 OutputFile
 AdditionalLibraryDirectories
 ProgramDatabaseFile
 ImportLibrary
 OutputFile

Here is an example of how such a change would look alike:

 <Configuration
 	Name="DLL Unicode Debug|Win32"
 	OutputDirectory=".\..\..\lib\vc_dll\$(PlatformName)"
 	IntermediateDirectory=".\vc_mswuddll\$(PlatformName)\adv"
 	ConfigurationType="2"
 	InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
 	UseOfMFC="0"
 	ATLMinimizesCRunTimeLibraryUsage="false"
 	CharacterSet="1"
 	>
 ...
 	<Tool
 		Name="VCMIDLTool"
 		PreprocessorDefinitions="WIN32,_USRDLL,DLL_EXPORTS,_DEBUG,__WXMSW__,__WXDEBUG__,_UNICODE,WXUSINGDLL,WXMAKINGDLL_ADV"
 		MkTypLibCompatible="true"
 		SuppressStartupBanner="true"
 		TargetEnvironment="1"
 		TypeLibraryName=".\..\..\lib\vc_dll\$(PlatformName)/wx_adv.tlb"
 		HeaderFileName=""
 	/>
 	<Tool
 		Name="VCCLCompilerTool"
 		AdditionalOptions="/EHsc "
 		Optimization="0"
 		AdditionalIncludeDirectories="..\..\lib\vc_dll\$(PlatformName)\mswud,..\..\include,..\..\src\tiff,..\..\src\jpeg,..\..\src\png,..\..\src\zlib,..\..\src\regex,..\..\src\expat\lib"
 		PreprocessorDefinitions="WIN32;_USRDLL;DLL_EXPORTS;_DEBUG;__WXMSW__;__WXDEBUG__;WXUSINGDLL;WXMAKINGDLL_ADV"
 		MinimalRebuild="true"
 		BasicRuntimeChecks="3"
 		RuntimeLibrary="3"
 		RuntimeTypeInfo="true"
 		UsePrecompiledHeader="2"
 		PrecompiledHeaderThrough="wx/wxprec.h"
 		PrecompiledHeaderFile="vc_mswuddll\$(PlatformName)\wxprec_advdll.pch"
 		AssemblerListingLocation=".\vc_mswuddll\$(PlatformName)\adv/"
 		ObjectFile=".\vc_mswuddll\$(PlatformName)\adv/"
 		ProgramDataBaseFileName="..\..\lib\vc_dll\$(PlatformName)\wxmsw270ud_adv_vc_custom.pdb"
 		WarningLevel="4"
 		SuppressStartupBanner="true"
 		DebugInformationFormat="3"
 	/>
 	<Tool
 		Name="VCManagedResourceCompilerTool"
 	/>
 	<Tool
 		Name="VCResourceCompilerTool"
 		PreprocessorDefinitions="_DEBUG,__WXMSW__,__WXDEBUG__,_UNICODE,WXDLLNAME=wxmsw270ud_adv_vc_custom,WXUSINGDLL,WXMAKINGDLL_ADV"
 		Culture="1033"
 		AdditionalIncludeDirectories="..\..\lib\vc_dll\$(PlatformName)\mswud;..\..\include;..\..\src\tiff;..\..\src\jpeg;..\..\src\png;..\..\src\zlib;..\..\src\regex;..\..\src\expat\lib"
 	/>
 	<Tool
 		Name="VCPreLinkEventTool"
 	/>
 	<Tool
 		Name="VCLinkerTool"
 		AdditionalDependencies="wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib wxregexud.lib wxexpatd.lib winmm.lib comctl32.lib rpcrt4.lib wsock32.lib odbc32.lib ..\..\lib\vc_dll\$(PlatformName)\wxmsw27ud_html.lib ..\..\lib\vc_dll\$(PlatformName)\wxbase27ud_xml.lib ..\..\lib\vc_dll\$(PlatformName)\wxmsw27ud_core.lib ..\..\lib\vc_dll\$(PlatformName)\wxbase27ud.lib"
 		OutputFile="..\..\lib\vc_dll\$(PlatformName)\wxmsw270ud_adv_vc_custom.dll"
 		LinkIncremental="2"
 		SuppressStartupBanner="true"
 		AdditionalLibraryDirectories="..\..\lib\vc_dll\$(PlatformName)"
 		GenerateDebugInformation="true"
 		ProgramDatabaseFile=".\..\..\lib\vc_dll\$(PlatformName)/wxmsw270ud_adv_vc_custom.pdb"
 		ImportLibrary="..\..\lib\vc_dll\$(PlatformName)\wxmsw27ud_adv.lib"
 		TargetMachine="1"
 	/>
 	<Tool
 		Name="VCALinkTool"
 	/>
 ...
 	<Tool
 		Name="VCXDCMakeTool"
 	/>
 	<Tool
 		Name="VCBscMakeTool"
 		SuppressStartupBanner="true"
 		OutputFile=".\..\..\lib\vc_dll\$(PlatformName)/wx_adv.bsc"
 	/>
 	<Tool
 		Name="VCFxCopTool"
 	/>
 	<Tool
 		Name="VCAppVerifierTool"
 ...
 	<Tool
 		Name="VCPostBuildEventTool"
 	/>
 </Configuration>

Again: These changes have to be done to all *.vcproj! Yes, this is a lot of work. Maybe someone can write a script which works with tools which are included by default in Windows (like VBScript or similar).


Changing mostly automatic using Visual Studio

This method only works if you solely use wxWidgets (2.9+) statically using the Debug or Release configuration. It requires a lot less manual work than the previous method.

Make the following three replacements using Visual Studio's "Replace in Files" option (Ctrl+Shift+H, or Edit > Find and Replace > Replace in Files) to all wx_vc9*.vcproj (assuming you use Visual Studio 2008, if not then replace with 7 or 8 as needed) files in build\msw\:

Replace:

OutputDirectory="..\..\lib\vc_lib"

with:

OutputDirectory="$(PlatformName)\$(ConfigurationName)"

Replace:

lib\vc_lib\

with:

lib\vc_lib\$(PlatformName)\

Replace:

vc_msw

with:

$(PlatformName)\vc_msw

Editing setup.h in the directory include/msvc/wx:

Replace the single line:

   #define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, wxARCH_SUFFIX, _lib)

with these multiple lines:

   #ifdef _M_X64
       #define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _lib, /x64)
   #else
       #define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _lib, /Win32)
   #endif

The below changes to setup.h are not needed.

Editing setup.h in the directory include/msvc/wx:

NB: you don't need to do this with wxWidgets 2.9 in which msvc/wx/setup.h was modified to use the correct paths out of the box, the instructions below are for wxWidgets 2.8 only!


(There are several files named setup.h in the wxWidgets directory tree. Please be careful to modify the correct one.)

It's difficult to describe what you need to do now. In this case examples are better than words, so here it goes:

The unmodified setup.h might look like this

 ...
       #ifdef WXUSINGDLL
           #ifdef _DEBUG
               #include "../../../lib/vc_dll/mswud/wx/setup.h"
           #else
               #include "../../../lib/vc_dll/mswu/wx/setup.h"
           #endif
       #else
           #ifdef _DEBUG
               #include "../../../lib/vc_lib/mswud/wx/setup.h"
           #else
               #include "../../../lib/vc_lib/mswu/wx/setup.h"
           #endif
       #endif
 ...
   #else // !_UNICODE
       #ifdef WXUSINGDLL
           #ifdef _DEBUG
               #include "../../../lib/vc_dll/mswd/wx/setup.h"
           #else
               #include "../../../lib/vc_dll/msw/wx/setup.h"
           #endif
       #else // static lib
           #ifdef _DEBUG
               #include "../../../lib/vc_lib/mswd/wx/setup.h"
           #else
               #include "../../../lib/vc_lib/msw/wx/setup.h"
           #endif
       #endif // shared/static

The modified setup.h must look like this

 ...
       #ifdef WXUSINGDLL
           #ifdef _DEBUG
 #ifdef _WIN64
               #include "../../../lib/vc_dll/x64/mswud/wx/setup.h"
 #else
               #include "../../../lib/vc_dll/Win32/mswud/wx/setup.h"
 #endif
           #else
 #ifdef _WIN64
               #include "../../../lib/vc_dll/x64/mswu/wx/setup.h"
 #else
               #include "../../../lib/vc_dll/Win32/mswu/wx/setup.h"
 #endif
           #endif
       #else
           #ifdef _DEBUG
 #ifdef _WIN64
               #include "../../../lib/vc_lib/x64/mswud/wx/setup.h"
 #else
               #include "../../../lib/vc_lib/Win32/mswud/wx/setup.h"
 #endif
           #else
 #ifdef _WIN64
               #include "../../../lib/vc_lib/x64/mswu/wx/setup.h"
 #else
               #include "../../../lib/vc_lib/Win32/mswu/wx/setup.h"
 #endif
           #endif
       #endif
 ...
   #else // !_UNICODE
       #ifdef WXUSINGDLL
           #ifdef _DEBUG
 #ifdef _WIN64
               #include "../../../lib/vc_dll/x64/mswd/wx/setup.h"
 #else
               #include "../../../lib/vc_dll/Win32/mswd/wx/setup.h"
 #endif
           #else
 #ifdef _WIN64
               #include "../../../lib/vc_dll/x64/msw/wx/setup.h"
 #else
               #include "../../../lib/vc_dll/Win32/msw/wx/setup.h"
 #endif
           #endif
       #else // static lib
           #ifdef _DEBUG
 #ifdef _WIN64
               #include "../../../lib/vc_lib/x64/mswd/wx/setup.h"
 #else
               #include "../../../lib/vc_lib/Win32/mswd/wx/setup.h"
 #endif
           #else
 #ifdef _WIN64
               #include "../../../lib/vc_lib/x64/msw/wx/setup.h"
 #else
               #include "../../../lib/vc_lib/Win32/msw/wx/setup.h"
 #endif
           #endif
       #endif // shared/static
 ...

Automatic Python script

Ian Mallett provides the following Python script that makes all the changes automatically. Standard disclaimer.

   import os
   
   #CHANGE THIS!!!
   dir_prefix = "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/wxWidgets-2.9.4/"
   
   for dirname, dirnames, filenames in os.walk(dir_prefix+"build/msw/"):
       for filename in filenames:
           if filename.startswith("wx_vc9") and filename.endswith(".vcproj"):
               path = dirname + filename
   
               file = open(path,"r")
               data = file.read()
               file.close()
   
               data = data.replace(
                   "OutputDirectory=\"..\\..\\lib\\vc_lib\"",
                   "OutputDirectory=\"$(PlatformName)\\$(ConfigurationName)\""
               )
               data = data.replace(
                   "OutputDirectory=\"..\\..\\lib\\vc_dll\"",
                   "OutputDirectory=\"$(PlatformName)\\$(ConfigurationName)\""
               )
               data = data.replace(
                   "lib\\vc_lib\\",
                   "lib\\vc_lib\\$(PlatformName)\\"
               )
               data = data.replace(
                   "lib\\vc_dll\\",
                   "lib\\vc_dll\\$(PlatformName)\\"
               )
               data = data.replace(
                   "vc_msw",
                   "$(PlatformName)\\vc_msw"
               )
               data = data.replace( #Must come after the others
                   "AdditionalLibraryDirectories=\"..\\..\\lib\\vc_dll\"",
                   "AdditionalLibraryDirectories=\"..\\..\\lib\\vc_dll\\$(Platform)\""
               )
   
               file = open(path,"w")
               file.write(data)
               file.close()
   
   file = open(dir_prefix+"include/msvc/wx/setup.h","r")
   data = file.read()
   file.close()
   
   data = data.replace(
       "#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, wxARCH_SUFFIX, _dll)",
       """#ifdef _M_X64
       \t#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _dll, /x64)
       #else
       \t#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _dll, /Win32)
       #endif"""
   )
   data = data.replace(
       "#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, wxARCH_SUFFIX, _lib)",
       """#ifdef _M_X64
       \t#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _lib, /x64)
       #else
       \t#define wxLIB_SUBDIR wxCONCAT3(wxCOMPILER_PREFIX, _lib, /Win32)
       #endif"""
   )
   
   file = open(dir_prefix+"include/msvc/wx/setup.h","w")
   file.write(data)
   file.close()

Final Notes

I have done this with the HEAD version of CVS and it works. Unfortunately, I don't know if the samples will compile and link seamless with these changes. If they don't work, you will need to change the project file similar to above.