I use the TFS 2008 build facilities. I have a large MSBuild project (TFSBuild.proj) and I wanted to split it into a few files because it is becoming hard to maintain.
I found a strange behavior; when I extracted one of the targets (BeforeInitializeWorkspace) to a separate file and then imported it into the main *.proj file, it was not executed. Although, in my MSBuild log, there was information that the target has been imported and overridden, but hasn't been executed. If I have the same target defined in my main *.proj file, it is executed. Can someone explain why the target isn't executed when imported from a file?
Thanks,
Me being stupid ;)
I had the order of <Import> wrong. The first file to import was my overridden target, then the Microsoft.TeamFoundation.Build.targets was imported and overrode my target.
Anyway, changing the order helped. So now, the Microsoft.TeamFoundation.Build.targets is the first target to import and then all my other targets.
Related
We are including separate repositories into a common CMake superproject (which simply add_subdirectory() each repository folder, in the correct dependency order).
The different repositories all rely on export() to ouptut a XxxTargets.cmake file, such as:
# Assumes this repository provide the 'Alpha' target
install(TARGETS Alpha EXPORT AlphaTargets)
export(EXPORT $AlphaTargets
FILE $AlphaTargets.cmake
NAMESPACE myrepo::)
Yet, this superproject approach allowed us to observe that the export does not create the file directly. We could draw this conclusion because when the generated file is include() from another repository (added later, with a subsequent add_subdirectory()), the file does not exist yet.
Why is export() delaying the file creation?
And more importantly, is there a way to force it to actually create the file before the next add_subdirectory()?
Why is export() delaying the file creation?
Because you are asking it to generate code for a particular export set, which isn't fully defined until the configure step ends. If it generated it immediately, then the behavior of export() and install(EXPORT) would be vexing and inconsistent.
And more importantly, is there a way to force it to actually create the file before the next add_subdirectory()?
The export(TARGETS) signature runs immediately as far as I know. But I also can't think of a single reason why you would need the generated exports file when working with add_subdirectory. The targets already exist, so there's no need to import them! If the names are different, create ALIAS targets as needed.
Lets make obscure question simple...
We have a solution which consists of many projects and some of them have set Custom build events using 3rd party stuff for some dark magic compilation and looks similar like this:
<CustomBuild Include="..\folder\somestuff.xyz">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">C:\Tcl\bin\tclsh.exe $(APP_PATH)\modules\APP\bin\generator.tcl -o %(RelativeDir)%(Filename) %(RelativeDir)%(Filename).xyz</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">APPGEN %(RelativeDir)%(Filename)</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir)%(Outputs)</Outputs>
</CustomBuild>
This was working properly until we switch form VS2015 to VS2019 as now during the compilation it reports that:
Project is not up-to-date: build output 'd:\projects\program\app\src\plugins\shared\' is missing. This would be more or less ok, but it forces the compiler to recompile also the dependencies of this project and this start to be really annoying as you need to rebuild several projects everytime even when no changes were done.
I found out that the problem originates from this line of Custom build:
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir)%(Outputs)</Outputs>
More precisely from this part: %(RelativeDir)%(Outputs) as the check for .cpp and .h file in the same tag do not generate any issues. So I removed this check for directory. When this chunk of code is removed the project compiles properly and do not re-compile all day long.
So why the Custom build's Output check is now working properly just with files and directories are generating this kind of issue?
And yes, the examined dir exists and it refers to the existing correct path.
The real problem is that your real project is always rebuild due to the metadata Outputs.
The special point is that you should make sure the validity and legitimacy of the value of Outputs.
The problem is under %(RelativeDir) of %(RelativeDir)%(Outputs). When you add it, the outputs has an illegal folder structure rather than a file which makes the outputs always find the missing illegal folder structure so that causes the project always rebuild.
Let me describe it in detail,
when msbuild reads outputs proeperty, when it reads till %(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir), the value of Outputs is this:
..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\
Then, it reads %(Outputs)(reads itself), which is more like copy the above value twice:
..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\
You will find the last part ..\folder\ is not a file and it is a folder structure which is illegal for the outputs.
That is the reason.
And it is more like your problem that the folder structure d:\projects\program\app\src\plugins\shared\ is missing.
Suggestion
So you should not add outputs again.
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;</Outputs>
I would like to know, which code is compiled when i build the project in Objective-C - every single line of code in my project, or only those, that are called from the main.c and then from the ones that are called from them?
I mean, does the compiler separate the project to the simply connected domains and compiles the one that is linked to the main, or it just compiles it all?
Thank you, guys!
The compiler does not perform semantical analysis on your code. It compiles exactly what you tell it to compile -- Xcode generally invokes the compiler in a way that it compiles every file into your application. However, it's unnecessary to compile/link the files from which no classes/functions are used; although not compiling files from which you use classes/functions results in a linkage error (that is, the compiler won't be able to find some symbols in the binary file while putting together the object code for the final executable).
All files in your project get compiled, except for the header files that are not included from any of the .m files, or headers the inclusion of which is suppressed conditionally.
A Xcode project consists of one or more targets.
For each target you can define, what *.m-files get compiled
if you add a new file to the project, you can specify to what target it will be added. (actually this is a place, where I often see, that the main target is not selected — beware)
I read John Robbins' article TFS 2010 Build Number and Assembly File Versions: Completely In Sync with Only MSBuild 4.0, and I'm wondering about the best way to go about integrating this.
The download for the article has two files, one is a targets file and one is a proj file.
The targets file has a number of tasks to scrape out a build number based on the Tfs build number (the same one used for the builds) and write that number out to some location (call it BuildNumberFile) for consumption by other proj files.
The proj file is very simple. It just imports the aforementioned targets file, and then declares a target with name "All" while also declaring DefaultTargets on the Project element to be All as well.
<Project ToolsVersion="4.0" DefaultTargets="All" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- The two required properties so the Wintellect.TFSBuildNumber tasks knows your major and minor values.-->
<TFSMajorBuildNumber>3</TFSMajorBuildNumber>
<TFSMinorBuildNumber>1</TFSMinorBuildNumber>
</PropertyGroup>
<Import Project="Wintellect.TFSBuildNumber.targets"/>
<!-- Just ask for the version information files you need. These are here to show all the diffent ones in
Wintellect.TFSBuildNumber.Targets. You can change the names -->
<Target Name="All"
DependsOnTargets="WriteSharedCSharpAssemblyVersionFile;
WriteSharedVBAssemblyVersionFile;
WriteSharedCPPCLIAssemblyVersionFile;
WriteSharedCPPAssemblyVersionFile;
WriteSharedWiXAssemblyVersionFile;
WriteSharedTextAssemblyVersionFile;"/>
</Project>
I have two questions about this:
I'm still learning MSBuild. If the name of the target isn't specified elsewhere in the targets, is the target executed? How do I ensure that this target is run?
Are the csproj files supposed to declare an Include item for the location where BuildNumberFile is, even though it doesn't exist until compiletime?
Do ItemGroups and Include have a DependsOnTargets or something that allows them make sure the file exists before they build?
Are the entire contents of the csproj file using this supposed to be wrapped in a target that expresses DependsOnTargets for BuildNumberFile?
Thanks!
I think I've got this figured out, but two people promoted my question so I'll answer it here:
You can ensure that a target is run by expressing a dependency on it from another target. Microsoft.Common.targets exposes two targets--BeforeBuild and AfterBuild--expressly for the purpose of being overridden for customizability. I found the easiest way to do this was <Target Name="BeforeBuild" DependsOnTargets="WriteSharedCSharpAssemblyVersionFile" /> where WriteSharedCSharpAssemblyVersionFile is the target declared in the download from the link in the original post. Also, if you're new to MSBuild, this BeforeBuild target must be declared after the Microsoft.CSharp.targets is imported, but the default csproj template guides you in doing this.
The WriteSharedCSharpAssemblyVersionFile target should indeed write the file to some central location, since when building a solution, all targets are executed only once. All projects should reference the file from that location even if it doesn't exist, since by the time compilation happens (or more importantly, by the time references are resolved), the BeforeBuild target will have run and the file will be in place.
In my structure, I have these versioning files in a folder directly underneath the branch root folder. Furthermore, since the file being built is generated, I have it build to the output directory. It seems a little strange to be referencing things from the output, but it preserves the invariant of having all build products in one place so that the output directory can be blown away as a means of performing a clean.
In MSBuild items constitute inputs into the system (usually files) so it's weird to think of them depending on targets. After some learning this question doesn't make a lot of sense. In any case, the answer is no.
The entire contents of the file should indeed not be all in one target--all that is required is to import the Wintellect.TFSBuildNumber.targets file at the beginning of your csproj file, and declare BeforeBuild's dependency on WriteSharedCSharpAssemblyVersionFile at the end.
Hope this helps!
I have a source XML file that is used to create C# files that are then compiled as part of a project.
Currently I have a BeforeBuild target that runs my XML to C# converter.
The problem is that by the time the BeforeBuild step is run the old files appear to have been stored by the build system so the new files are ignored.
How can I get around this? It seems that Transforms would be the way but they are limited in what they can do.
I guess your "stored by the build system" can be translated as the ItemGroup containing the .cs files you wish to compile is generated when the msbuild file is read, as opposed to when your compile target is executed. You have several options:
<CreateItem> see CreateItem task
<Output> see Output element
I hope this helps.
Well we have something similar-ish here. We gen a .cs off an xml file using a .tt. Both files are part of a specific csproj. Going properties->BuildEvents on the csproj gives this little snippet in the Pre-build event command line:
del "$(ProjectDir)MyCsFile.cs"
copy /b /y "$(ProjectDir)\MyXmlFile.xml" "$(TargetDir)"
"$(ProjectDir)tt.bat" "$(ProjectDir)MyTemplateFile.tt"
No idea if that's of any use to you, I hope it might suffice as a last chance workaround.
I think you need to show us a little of your rule/build file. You should have a rule/dependency for the cs file that has the xml as the dependency.
I am not sure what you mean by "stored by the build system"
Check your rules carefully for errors/omissions.