It's not exactly easy for me to summarize this... I have this structure on disk:
[dir] project
[dir] foo
[file] foo.build
[dir] bar
[file] bar.build
[file] default.include
The file default.include contains a couple of properties which are the directories used during the build. E.g:
property name="build.dir" value="${directory::get-current-directory}".
The default.include file is included by foo.build and bar.build using its relative path:
include buildfile="..\default.include"
Now the problem: when I run foo.build from project\foo dir, I get the wrong value for build.dir. I need "project" and I get "project\foo" instead. Is there a way to get the directory in which the .include file exists?
I could do this in a batch file using %~dp0
you can specify the base directory of a project by using this
<property name="build.dir" value="${project::get-base-directory()}">
and make sure you set the build output path to be build.dir
You could set the build path property to be the relative difference between the working folder and the project root before including your shared include stuff. So, in \project\foo\foo.build:
<property name="build.dir" value="..\" />
<include buildfile="..\default.include" />
If you want to then refer to things relative to the project root then just build paths from build.dir. Let's say you had a \project\utilities\ folder where you put some custom build tools or something, then you can refer to that folder as:
<property name="utils.dir" value="${build.dir}utilities\" />
utils.dir would be ..\utilities\ which would be the right value from your working folder (\project\foo\ in this case).
Personally I do things the other way around - I have the main build file at the root of the project and it includes a build file for each sub-project. Physically the build is distributed across the projects, but logically it all runs as if it were one big script in the project root. The downside being that global property names and target names can collide so you need a naming convention to prevent that from happening.
Just got exactly the same problem:
NAnt - how to get the directory path of the included script
In my include file I need to get the directory of the include file, to refer to something else relative to it.
Seems like when NAnt includes another build file, it includes the content of it, without changing anything in its environment (directory::get-current-directory, project::get-buildfile-path, etc).
Another solution in your case might be to use <nant> task instead of <include>. Obviously it works if you don't need anything returned from the included script and just want to run it.
Related
I have a console application that has <TargetFramework>net6.0</TargetFramework>. I am trying to use the exe of this console application in the wix project for creating the setup as shown below:
<Component Id="_COMP_ConsoleApp_exe" Guid="{34407E06-98A0-4CF3-8021-F9533CFE537D}">
<File Id="_FILE_ConsoleApp_exe" Name="ConsoleApp.exe" KeyPath="yes" Source="$(var.ProjectSourceDir)\ConsoleApp.exe" />
</Component>
But during the build it gives the error "The system cannot find the file ..\Release\ConsoleApp.exe". The ConsoleApp.exe is getting created in the Release folder.
That error indicates the file is not in the location you specified. To debug, try putting the full path to the file on your computer in the File/#Source attribute. Once you know you have the right path, then try using BindPaths or, if you must, preprocessor variables to make the location more generic.
I expect you'll find the folder ..\Release\ is not the one you thought it was.
Note: the Name and KeyPath attributes are unnecessary as they will default to those values.
I am currently working on changing our codebase to use Nuget. As part of the process the copying of ressources to the output directory should be moved from postbuild events in the projects to the files tag in the .nuspec file.
For the particular project the ressource was called Resources.resx and is renamed to something more specific during the copy (yes I know great programming - not mine and not my place to change it).
Is it possible to change the filename using the file node in nuspec or do I need to keep a postbuild in this case?
My attemp of renaming it with the target property fails:
< file src="foo/bar.resx" target="foo/foobar.resx"/>
creates the following output:
"foo/foobar.resx/bar.rex"
I found a familiar problem on github but it was rejected due to being posted on a dead branch and not trying to rename a file but change its type.
https://github.com/NuGet/Home/issues/2019
Thanks for the help
This functionality is not built into NuGet. The only conceivable way to do this would be to implement a powershell script (install.ps1) that would handle the rename of both the file and the csproj.
Late to the party, but this looks like it could work:
From: https://learn.microsoft.com/en-us/nuget/reference/nuspec
Renaming a content file in the package
Source file:
ie\css\style.css
.nuspec entry:
<file src="ie\css\style.css" target="Content\css\ie.css" />
Packaged result:
content\css\ie.css
Edit:
I found this post (https://stackoverflow.com/a/45601252/182888) where it says:
Note: The File extension in src and target must match or the specified target will be treated like a directory.
So keep that in mind or it might trip you up.
I currently have multiple projects being build using msbuild. I have a small customisation to the build that is handled by a .targets file. One solution is to add the snippet
<Import Project="MyTargets.targets"/>
to each project file. However, ideally I would like to not touch the project files, and be able to pass this information as a parameter to msbuild. That way I could easily control whether I run this customisation from the command line, and I don't have to touch the existing project files.
Is this possible?
You can do that easily with MSBuild 4.0 (check your version by top-level attribute ToolsVersion="4.0"):
There are multiple properties you can use to import your targets before and after Common.targets and or CSharp.targets loaded.
Simplest way is to use 2 sets of self explaining properties.
First set is:
$(CustomBeforeMicrosoftCommonTargets)
$(CustomAfterMicrosoftCommonTargets)
and second one:
$(CustomBeforeMicrosoftCSharpTargets)
$(CustomAfterMicrosoftCSharpTargets)
Property names are pretty self-explained.
Just pass full file name to any of this properties via msbuild.exe
e.g.
msbuild.exe /p:CustomBeforeMicrosoftCSharpTargets=c:\mytargets\custom.targets
You can use other "ImportByWildcard(Before|After)...." properties if you need to import multiple files. But in that case you need to pass more parameters to command-line.
Starting from MSBuild 15.0, the following two files are auto-imported into your build in case they are found on the project path or in any parent folder on the path to the root directory:
Directory.Build.props
Directory.Build.targets
Remark: once the props or targets file is found, MSBuild will stop looking for a parent one.
Also see: https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build
Lets say you have a project file called "Project.msbuild". You would add this conditional import:
<Import Project="$(TargetToImport)" Condition="'$(TargetToImport)' != ''" />
Then pass the name of the target file you want to import as an msbuild property:
msbuild.exe Project.msbuild /p:TargetToImport="TargetFile.Target"
Make sure you use an absolute path to the target file and it works.
Source: Sayed Ibrahim Hashimi - MSBuild how to execute a target after CoreCompile part 2.
msbuild.exe /p:CustomBeforeMicrosoftCSharpTargets="c:\mytargets\custom.targets" /preprocess:out.xml
Use /preprocess[:filepath] to see the result of the imports.
You don't have to modify any csproj or vbproj files.
Of course, it only works where you can set MSBuild Properties.
for some reason when I reopen my intellij projects, the iml files’ root tags’ url parameter is automatically replacing my user-defined local variable with $USER_HOME$.
Furthermore, when I go in and manually replace (with CTRL+R) the $USER_HOME$ with the $LOCAL_VAR$, Intellij replaces this change with $LOCAL_VAR$/.m2/repository. Have you ever run into this issue?
code from one of the directory .iml files:
<library>
<classes>
<root url="jar://$LOCAL_VAR$/.m2/repository/.m2/repository/bar/foo.jar!/" />
</classes>
<JAVADOC/>
</libarary>
When I go and replace the $LOCAL_VAR$/.m2/repository with $LOCAL_VAR$ for the second time, no further autoreplacements occur. The reason why I need to replace $USER_HOME$ with $LOCAL_VAR$ is because $USER_HOME$ is system-defined, and I need to point my code to a SAMBA drive that I've mounted onto my Windows7 pc.
If you can please suggest either a way to override my $USER_HOME$ or a possible cause of this odd behavior, I would be grateful for your wisdom. Please note that when I originally imported this project, I had generated the .iml files from a .ipr file. Not sure if that's relevant.
Try to define /.m2/repository/ as a separate path variable, this one should not be overridden.
I've been desperately looking for the answer to this and I feel I'm missing something obvious.
I need to copy a folder full of data files into the TARGETDIR of my deployment project at compile time. I can see how I would add individual files (ie. right click in File System and go to Add->File) but I have a folder full of data files which constantly get added to. I'd prefer not to have to add the new files each time I compile.
I have tried using a PreBuildEvent to copy the files:
copy $(ProjectDir)..\Data*.* $(TargetDir)Data\
which fails with error code 1 when I build. I can't help but feel I'm missing the point here though. Any suggestions?
Thanks in advance.
Graeme
Went to this route.
Created a new project (deleted the default source file Class1)
Added the files/folders necessary to the project.
Added the project as project output in the installer, choosing the option content files.
This removes the complexity of having to zip/unzip the files as suggested earlier.
Try
xcopy $(ProjectDir)..\Data\*.* $(TargetDir)Data /e /c /i [/f] [/r] /y
/e to ensure tree structure fulfilment (use /s if you want to bypass empty folders)
/c to continue on error (let the build process finish)
/i necessary to create the destination folder if none exists
/y assume "yes" for overwrite in case of previously existing files
[optionnal]
/f if you wanna see the whole pathes resulting from the copy
/r if you want to overwrite even previously copied read-only files
The method is simpler on the project than on files, yes. Beside, on files, it copies only the modified/missing files on each build but forces you to maintain the project on each data pack modification. Depends on the whole data size and the variability of your data pack.
Also beware the remaining files if you remove some from your data pack and rebuild without emptying your target folder.
Good luck.
I solved the problem by a workaround:
Add a build action of packaging entire directory (could be filtered) to a ZIP file.
Add a reference to an empty ZIP file to deployment project.
Add a custom action to deployment project to extract the ZIP to destination folder.
It's simple and stable.
Your error is probably because your path has spaces in it and you don't have the paths in quotes.
ex copy "$(ProjectDir)..\Data*.*" "$(TargetDir)Data\"
I need to do a similar thing. Thinking a custom action...
I found a different workaround for this. I added a web project to my solution that points at the data directory I want included in the deployment project. The web project automatically picks up any new files in the data directory and you can refer to the project content in the deployment project.