Cannot build Content.mgcb from command line due to errors with relative paths

Building our Content.mgcb file works fine when executed from Visual Studio or from the Pipeline tool itself. I am currently trying to get things working via a build script so we can get some build automation set up. However, I am running into problems due to the relative paths from the assets.

For reference, here are the paths where everything is located:
Content.mgcb - D:\project\code\project\Content
MGCB.exe - D:\project\bin
BuildAssets.bat - D:\project\bin
Debug.spritefont - D:\project\assets\fonts

I am running BuildAssets.bat, which simply runs the following:
MGCB.exe /platform:Windows /@:…/code/project/Content/Content.mgcb /outputDir:Content /intermediateDir:ContentTemp

And finally, the important parts of the Content.mgcb file:
#----------------------------- Global Properties ----------------------------#

/outputDir:..\..\..\bin\Content
/intermediateDir:obj/$(Platform)
/platform:Windows
/config:
/profile:Reach
/compress:False

#---------------------------------- Content ---------------------------------#

#begin ../../../assets/fonts/Debug.spritefont
/importer:FontDescriptionImporter
/processor:FontDescriptionProcessor
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Compressed
/build:../../../assets/fonts/Debug.spritefont;Fonts/Debug.spritefont

The errors I’m seeing are:
D:/project/bin/…/…/…/assets/fonts/Debug.spritefont
D:/project/bin/…/…/…/assets/fonts/Debug.spritefont: error: The source file ‘D:/project/bin/…/…/…/assets/fonts/Debug.spritefont’ does not exist!

The error makes sense, because that relative path is the path from the Content file, not the MGCB exe. But why is looking for a relative path from where the MGCB file is called instead of the Content file. Is this a bug? I tried setting the workingDir but I still got the same error (though it did properly change where it made the Content and ContentTemp folders).

I’m sure I could hack around this but updating my batch file to change the directory to where the Content file is run and execute everything from there, but it seems like this isn’t something I should need to do. Has anyone run into similar issues or been able to successfully build their Content file from a different directory?

Have you tried moving BuildAssets.bat inside the D:\project\assets\ ?
You can also try to move the .mgcb file.

Try this,
move the .mgcb in the same directory with your assets. (D:\project\assets\Content.mgcb)
and create an external link in the .csproj.

  <ItemGroup>
    <MonoGameContentReference Include="..\..\assets\content.mgcb">
    <Link>Content\content.mgcb</Link>
  </ItemGroup>  

finally, you have to include all the generated files.

  <ItemGroup>
    <Content Include="..\..\assets\Content\**">
      <Link>Content\%(RecursiveDir)%(Filename)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
1 Like

You can set the working dir with this batch command:

START /D D:\project\code\project\Content MGCB.exe /@:Content.mgcb

However there seems to be a bug in the destination path of a content item afterwards. You would need to delete this path like this:

/build:../../../assets/fonts/Debug.spritefont;Fonts/Debug.spritefont

becomes this:

/build:../../../assets/fonts/Debug.spritefont

Building works then.

Unfortunatley the output directory is also bugged then. You will find the XNB files here:

D:\project\code\assets\fonts\

and the intermediate files here:

D:\project\code\project\assets\fonts\

I don’t know why this happens, but you could simply copy all the generated XNB files to the right output directory like this:

xcopy /s /y ..\code\assets\fonts\** ..\code\project\Content\Content

Here is the full batch file:

@echo off

cd /d %~d0%~p0

START /WAIT /D D:\project\code\project\Content MGCB.exe /@:Content.mgcb

xcopy /s /y ..\code\assets\fonts\** ..\code\project\Content\Content

pause

When adding content files directly to the place where the content response file is located (D:\project\code\project\Content) then those bugs won’t occure and everything works just fine. So it seems that it does have something to do with the relative pathings.

1 Like

Thanks nkast and sqrMin1, both your answers do in fact fix the issue. They also led to me to do a little more debugging and figure out exactly WHY the workingDir command wasn’t working, as it really should address this exact issue.

Turns out, workingDir does fix the issue. Sort of. However, it ONLY works if you call MGCB.exe with the workingDir command coming BEFORE the “@” parameter (which specifies the Content.mgcb file.

Doing some digging in the MGCB code, most if not all of the command line parameters are executed immediately and in the order they are read, instead of being saved off and used in the order where they would have effect. So what was happening is that as soon as the CommandLineParser read my command line arguments, it took the “/@:…/code/project/Content/Content.mgcb” parameter and immediately parsed through that file making a list of ContentItem objects. All of these would use Directory.GetCurrentDirectory() and the relative path in the file to construct the path. However, this path always just refers to wherever MGCB call is coming from. Later, when the /workingDir command gets read, it calls Directory.SetCurrentDirectory(path);. However, this does nothing because the list of ContentItems has already been created and the paths set.

Moving the workingDir to the first parameter does indeed fix the problem where it cannot find the assets. It will find and build them. However, as sqrMin1 mentions, the output directory then breaks because everything still references Directory.GetCurrentDirectory() and combines that with the parameters, and the current directory has been changed to workingDir at this point.

So TLDR:
MGCB is pretty wonky when being called from the command line, and the workingDir parameter is pretty finicky.

It is very weird to send the same parameter multiple times, but the following code DOES work in the command line:
MGCB.exe /workingDir:…/code/project/Content/ /platform:Windows /@:…/code/project/Content/Content.mgcb /workingDir:%~dp0 /outputDir:Content /intermediateDir:ContentTemp

Basically it will set the workingDir to the Content folder, then it will execute the “/@” parameter using that directory and make the list of items to build. Then, the second workingDir parameter will set the path to the path back to where the batch file is so that the output and intermediate dirs. will be properly relative.

1 Like

Pretty interesting. I just tried your solution and can confirm that it’s working the way you’ve described it.

I bookmark your post in case it will be needed in the future.

Thanks for sharing your findings!

And good luck with your project :slight_smile:

1 Like