Search code examples
wixtfsbuildsql-server-data-tools

WiX project that references an SSDT project fails to build in TFSBuild - Undefined preprocessor variable '$(var.DatabaseProject.TargetDir)'


My project which is part of a larger solution was converted from a dbproj to asqlproj (SSDT). The solution includes a WiX installer which references the SSDT project. The WiX project builds fine on multiple developer systems through VS2010. The automated builds that we've always used, however, are failing with this error:

error CNDL0150: Undefined preprocessor variable '$(var.DatabaseProject.TargetDir)'.

The solution has been built by TFS automated builds for many months without issue prior to this project being converted. I can see from the build log that the SSDT project is being built, here are some relevant lines from the build log:

Project "C:\B\1\SourcePath\Server\Server.wixproj" (8) is building "C:\B\1\SourcePath\Database\DatabaseProject.sqlproj" (12) on node 1 (default targets).
...
Done Building Project "C:\B\1\SourcePath\Database\DatabaseProject.sqlproj" (default targets).

I can also see that the .dacpac and .dll files for the database project are created and copied into the output directory that TFS build has redirected the projects to.

The reference to the database project seems fine and TFS build seems to know that it should be built, but WiX is complaining about the undefined preprocessor variable for TargetDir.

I must be missing something...Is the output redirect employed by TFS causing my issue? I'm not sure where to go from here and appreciate any help you can suggest.

MORE INFO

Looking at the log file for the build in more detail I can see that the parameters for the .sqlproj project aren't being passed on the command line to candle.exe. When I build locally in VS2010, I can see the expected parameters passed as follows (just like the other projects referenced by the WiX project):

-d"DatabaseProject.FullConfiguration=Release|AnyCPU"
-dDatabaseProject.Platform=AnyCPU
-dDatabaseProject.ProjectDir=C:\SourcePath\Database\
-dDatabaseProject.ProjectExt=.sqlproj
-dDatabaseProject.ProjectFileName=DatabaseProject.sqlproj
-dDatabaseProject.ProjectName=DatabaseProject
-dDatabaseProject.ProjectPath=C:\SourcePath\Database\DatabaseProject.sqlproj
-dDatabaseProject.TargetDir=C:\SourcePath\Database\sql\release\
-dDatabaseProject.TargetExt=.dll
-dDatabaseProject.TargetFileName=DatabaseProject.dll
-dDatabaseProject.TargetName=DatabaseProject
-dDatabaseProject.TargetPath=C:\SourcePath\Database\sql\release\DatabaseProject.dll

None of these parameters are being passed to candle.exe during the TFS build. I figured this information might be useful for helping answer the question.

Any help is greatly appreciated!


Solution

  • Based on @RobMenching's answer, you won't be able to rely on the SSDT project variable to be set by any command-line build, so you'll need to find another way to reference the project's output.

    Fortunately, in a standard TFS build, the output folders will be the same for all projects in a given build configuration. Assuming you haven't redirected the output somehow, you should be able to use any of the other projects (which are working properly) as the reference path. E.g., assuming that you have a DatabaseProject.sqlproj and an DataAccessProject.csproj in the solution, you should be able to do:

    <Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
        <?ifdef DatabaseProject.TargetDir ?>
            <File Id='foo' Name='foo' src='$(var.DatabaseProject.TargetDir)\foo.dacpac' />
        <?else?>
            <File Id='foo' Name='foo' src='$(var.DataAccessProject.TargetDir)\foo.dacpac' />
        <?endif?>
    </Component>
    

    For builds done inside VS2010, where each project is built to its own output folder, the correct preprocessor variable ought to be defined and it will use the first option. For TFS builds, where the preprocessor variable is not defined, TFS will have redirected the SSDT's output to the same folder as all of the other projects, so any one of the preprocessor variables should work just as well.