4

Edit: Martin provides a link below to a defect, which is now fixed and released.

I am a university student. I would like to use .NET Core for my coursework. To do so, my code needs to compile and run on the department Linux cluster, because that is what my instructors test my submissions on.

My sysadmin installed the recently-released .NET Core 2.0 RHEL package for me on a trial basis. I created, built, and ran the sample CLI projects Microsoft provides, and they worked. But my sysadmin was displeased because dotnet created at least one file in (global) /tmp, which remained there after I logged off.

-rw------- myuser mygroup /tmp/.NETCoreApp,Version=v2.0.AssemblyAttributes.cs

In principle, he'd prefer dotnet not create any files in /tmp that it doesn't clean up when its process is done. More than that, when he tried to build Microsoft's samples himself, it failed; dotnet tried to access the above file, which his user did not have read permissions for!

Ideally, dotnet wouldn't create any files with a lifetime different from the project it is building. To achieve this, any such files could live in the project directory — maybe under the bin subdirectory, so that a clean will purge them. Is there a way to make dotnet write these files there instead? Otherwise, can it least use transient filenames, to avoid the permissions conflict we encountered?

Whatever the solution is, it has to be systemwide, and it cannot depend on the good behavior of users. So something like asking the user to set $TMPDIR will not work.

Noah
  • 417
  • 1
  • 5
  • 10

1 Answers1

5

The easiest way would be to set the TMPDIR environment variable to a different location as MSBuild uses it to construct the path.

Another way to make msbuild use a local path for this file is to add a target like this to the csproj file:

<Target Name="SetTFMAssemblyAttributesPath"
      BeforeTargets="GenerateTargetFrameworkMonikerAttribute">
  <PropertyGroup>
    <TargetFrameworkMonikerAssemblyAttributesPath>$(IntermediateOutputPath)$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)</TargetFrameworkMonikerAssemblyAttributesPath>
  </PropertyGroup>
  <ItemGroup>
    <!-- GenerateTargetFrameworkMonikerAttribute doesn't add to @(FileWrites) for the global path -->
    <FileWrites Include="$(TargetFrameworkMonikerAssemblyAttributesPath)" />
  </ItemGroup>
</Target>

This will put it into the IntermediateOutputPath which is obj/{Debug/Release}/{TargetFramework}/. The added FileWrites item allows it to be cleaned on dotnet clean, which is not done for the global location to avoid race conditions during clean.

You can create a Directory.Build.targets file in your user directory / in the directory hierarchy your projects are in to wire up the target to all projects (unless they don't already contain a file with this name). Just surround the target with a <Project> element for this file.

There is a GitHub issue on changing the default location.

Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
  • Thank you, that is good to know -- although I do hope a solution which doesn't depend on user discipline can be found. – Noah Aug 30 '17 at 16:28
  • Yeah that's the workaround for ever project. I linked to it on the related GitHub issue (I'll add it to the answer). – Martin Ullrich Aug 30 '17 at 16:34
  • Added a suggestion for a `Directory.Build.targets` to add this logic to all projects you work on. If the answer works for you, please consider accepting the answer. – Martin Ullrich Sep 01 '17 at 17:08
  • That's a user setting for .NET, in a file residing under the user's home directory? It sounds sensible in itself, but does it solve the problem of a multiuser institutional system like ours? My admin needs it as a systemwide default for all current and future users. I don't think such a file can fulfill that purpose. It's too hard for the admin to force it to exist there, too easy for the user to delete -- and most users won't need it, because not everyone uses .NET. A Linux environment variable just for this (not **$TMPDIR**) would work, or an optional config file under the global **/etc**. – Noah Sep 03 '17 at 17:28
  • So if even resetting $TMPDIR just for the `dotnet` commands is not an option, then you're blocked. This would need a change in msbuild (linked GH issue) or a change to every project (like the `Directory.Build.targets` - it is imported into ever project but only if the project doesn't already have one) – Martin Ullrich Sep 03 '17 at 20:39
  • 1
    Got it. Thank you for your efforts, Martin. I will add my suggested solution to the GH issue, if you think that would be well-received. – Noah Sep 03 '17 at 21:09
  • I already commented on that issue linking to this questions but it couldn't hurt if you add a few words about your scenario. – Martin Ullrich Sep 03 '17 at 21:29
  • This is also an essential part of Directory.Build.targets if you want to achive incremental builds inside a docker container, since /tmp directory cannot be mounted under wsl (msbuild fails with error Failed to initialize CoreCLR, HRESULT: 0x80004005) – Gregor Slavec Jan 09 '20 at 14:49