To build on Windows I am using the makefile. I have a batch file that will call make with the platform I want to build. For Windows this simply calls make after setting up the environment. In Visual Studio I have set up an external tool on the menu for building. This tool uses the command output window and therefore parses the errors. So I can hit a button on the toolbar and build using make. Any errors are easily navigable into the source. This isn’t surprising as its using the MS compiler so the format is going to be correct. I like to be able to build on all platforms just as easily.
I do most of the development on Windows, and use VS to edit the files, even when working on OSX or Linux as I like its editor. I can’t directly compile on Windows though as I need to compile in either OSX or Linux. My setup is an OSX computer with a Windows VM and a Linux VM (using Vmware). I keep all the files I’m working on on OSX. They Linux and Windows VMs share those same folders using Vmware Shared Folders features (I could also use networking shares). I also have SSH setup from the Windows VM to OSX and Linux. To set off a build on Linux or OSX I use SSH to run make on the appropriate platform. They are all sharing the same files. The directories are simliar but have different bases.
For example on Windows the files are visible from Z:\. This maps to “~” (home directory) on OSX, and on Linux to /mnt/hgfs/osxhome. I have my Build.bat file take a command line parameter to determine which build to do. For example “Windows” to do the Windows build. “OSX” to do the OSX build. If OSX is selected it takes the directory name, and modifies it to the one used by OSX. By removing the drive letter and replacing back slashes with forward slashes. For example Z:\Code\WaterJuice\makefile becomes ~/Code/WaterJuice/makefile. In Linux it would be compe /mnt/hghs/osxhome/Code/WaterJuice/makefile.
So from Visual Studio I can press a button and call Build.bat with Windows, OSX, or Linux. When its OSX or Linux it changes the base name and then calls ssh to run make. The output is displayed in the Visual Studio command output window. This is almost perfect. I do not have to switch VMs, I stay with in Visual Studio and can build on any platform. However the output of GCC is slightly different from Visual studio so it is unable to detect the errors directly. I have a small filter I wrote in Perl that modifies the output to be Visual Studio compatible.
First the file names need to be modified. gcc will obviously output the filenames that it sees. In order for VS to open the correct file they need to be converted to the name the Windows sees. So for example when gcc outputs the file name ./lib/Md5.c (it uses relative paths), the Perl script converts this to Z:\Code\WaterJuice\lib\Md5.c. The other thing it does it change the line output of errors and warnings so that Visual studio recognises them.
Visual studio uses a line format such as:
lib\LibMd5.c(76): error C2065: 'variable' : undeclared identifier
Where as GCC would display the same error as
lib/LibMd5.c:76: error: ‘variable’ undeclared (first use in this function)
So a simple RegEx is used to convert the :nn: part to (nn): Now with the corrected path Visual Studio will bring up the file at the line number when I press F4.
Here is the Perl script I use. I call it GccToVss.pl
$| = 1; ( $actPath ) = @ARGV; while ( <STDIN> ) { # Replace UTF-8 quote marks with plain ascii s/\xe2\x80\x98/\'/g; s/\xe2\x80\x99/\'/g; # Convert error format and paths from gcc to vss s/([\w.\/]+):(\d+):(.*)/$actPath$1($2) : $3/; s/\//\\/g; print $_; }
It takes a single parameter which is the actual Windows directory where the root of the project is (the directory containing the makefile).
The following is Build.bat, the batch file that sets off the builds. It also caters for building in Cygwin and an x86 Windows XP build.
@echo off setlocal set RELPATH=%~p0 set RELPATH=%RELPATH:\=/% set ACTPATH=%~d0%~p0 set OSXBASE=~ SET OSXHOST=osxdev@10.0.1.10 set LINUXBASE=/mnt/hgfs/osxdev SET LINUXHOST=linuxdev@10.0.1.14 SET PROJECT=%2 %3 %4 %5 %6 %7 %8 %9 %~d0 cd %~p0 if /I "%1" == "Windows" goto Windows if /I "%1" == "WindowsXP" goto WindowsXP if /I "%1" == "Cygwin" goto Cygwin if /I "%1" == "OSX" goto OSX if /I "%1" == "Linux" goto Linux if /I "%1" == "All" goto All echo Syntax: echo Build ^<target^> echo ^<target^> options: echo Windows - Windows x64 Vista Build echo WindowsXP - Windows x86 XP Build echo Cygwin - Cygwin Build echo OSX - Remote OSX Build echo Linux - Remote Linux Build echo All - Builds ALL the above goto :eof :All set ALL=1 :Windows call "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" amd64 set CL=/link /LIBPATH:C:\WinDdk\7600.16385.1\lib\wlh\amd64 /LIBPATH:C:\WinDdk\7600.16385.1\lib\crt\amd64 /subsystem:console,6.0 echo. echo ::::::::::::: Building for Windows x64 Vista ::::::::::::::::: make echo ---- Build complete for Windows x64 Vista if "%ALL%" == "" goto :eof echo. :WindowsXP call "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 set CL=/link /LIBPATH:C:\WinDdk\7600.16385.1\lib\wxp\i386 /LIBPATH:C:\WinDdk\7600.16385.1\lib\crt\i386 /subsystem:console,5.1 echo ::::::::::::: Building for Windows x86 XP ::::::::::::::::: make echo ---- Build complete for Windows x86 XP if "%ALL%" == "" goto :eof echo. :Cygwin echo ::::::::::::: Building for Cygwin ::::::::::::::::: make 2>&1 | tools\GccToVss.pl %ACTPATH% echo ---- Build complete for Cygwin if "%ALL%" == "" goto :eof echo. :OSX echo ::::::::::::: Building for OSX ::::::::::::::::: ssh %OSXHOST% "cd %OSXBASE%%RELPATH%; make %PROJECT%" 2>&1 | tools\GccToVss.pl %ACTPATH% echo ---- Build complete for OSX if "%ALL%" == "" goto :eof echo. :Linux echo ::::::::::::: Building for Linux ::::::::::::::::: ssh %LINUXHOST% "cd %LINUXBASE%%RELPATH%; make %PROJECT%" 2>&1 | tools\GccToVss.pl %ACTPATH% echo ---- Build complete for Linux if "%ALL%" == "" goto :eof
The batch file contains a few hardcoded paths. They should be easy enough to modify to suit your environment.
This is as close as I can get to building directly from Windows itself. There is the possibility of using cross platform compilers on Cygwin to produce OSX and Linux binaries, but they are very complicated to setup. Plus I prefer to build on the native platform itself using the compilers provided.
Hopefully this article helps other people build Linux and OSX binaries from within Visual Studio.