3

I have a Batch file that's a library of functions like

:findmsbuild
if exist msbuildpath.txt (
    for /f %%i in (msbuildpath.txt) do set MSBUILD="%%i\MSBuild.exe"
) else (
    set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
    for /f "delims=" %%i in ('!VSWHERE! -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe') do set MSBUILD="%%i"
)
exit /b

And the official documentation for call says that I should be able to call directly to a label in another file like

call library.bat :findmsbuild

but what happens instead is, the interpreter executes library.bat from the first line. What am I doing wrong? The calling Batch file is approximately

setlocal enableextensions enabledelayedexpansion
cd "%~dp0"
call library.bat :findmsbuild
echo %MSBUILD%
aschipfl
  • 33,626
  • 12
  • 54
  • 99
Ansis Māliņš
  • 1,684
  • 15
  • 35
  • 2
    The syntax for the specified options / arguments to the `call` command are mutually exclusive. you cannot call a label outside of the current batch file. You could however place a goto statement in the called batch file that executes if the first argument is a valid label. – T3RR0R Jun 20 '22 at 13:03
  • 3
    For more correct documentation, see the third-party web page https://ss64.com/nt/call.html . It may be worth adding feedback to Microsoft's documentation page, though I don't think Microsoft care much about batch files these days. – k314159 Jun 20 '22 at 13:22
  • 2
    [see this](https://stackoverflow.com/a/30170342/388389) – elzooilogico Jun 20 '22 at 18:00

2 Answers2

1

What are you doing wrong? Trusting Microsoft's documentation.

You can either call externalbatch or call :internalroutine.

To do what you want, you'd need to put a line like goto %1 at the start of your library file - and remember then that the parameter list has the label at the start, so you'd need to shift it, and %* would retain the label as the first parameter.

Magoo
  • 77,302
  • 8
  • 62
  • 84
0

Preface: job / function is used interchangeably below.

It is possible to call functions in this way, however you need to script it into your library.bat program. That means assessing provided arguments, determining if they correspond to a valid job, and determining the action to take such as calling a job with %* arguments or providing help output.

Note: using Call %* to execute a label supplied as %1 when calling library.bat will:

  • desirable behaviour:
    • Allow arguments provided to a called job to reside in their intended positions as :jobname becomes %0 when called.
  • Potentially undesirable behaviours:
    • Result in the doubling of any carets present in the arguments. If relevent to any jobs, you'll need to account for that in the relevant job.
    • Expand any %variables% present in the argument string supplied to library.bat (defined or undefined)

An example of executing the desired functionality:

@Echo off

    Echo(

    Set "ExitCode=0"
    2> nul (
        Rem // search this file for labels matching Argument 1 at line beginning.
        %SystemRoot%\System32\Findstr.exe /BLI "%~1" "%~f0" > nul && (
            Call %* || (
                Call Set "ExitCode=%%Errorlevel%%"
                (Call )
            )
        ) || (
            Echo("%~1"|%SystemRoot%\System32\Findstr.exe /R "[:][.]*" && (
                Rem // No labels matching Argument 1 at line beginning. Argument 1 begins with a ":"
                Echo(Invalid job. Valid jobs:
                For /f "tokens=1" %%J in ('%SystemRoot%\System32\Findstr.exe /R "^[:][.]*" "%~f0"')Do Echo(%%J
                Exit /b 1
            ) || If not "%~1" == "" (
                Rem // Argument 1 does not begin with a ":"
                Echo(No job call attempt. Args: %*
                Echo(
                Echo(To call a job:
                Echo(Call "%~f0" :jobname %%*
            )
        )
    )

Exit /b %ExitCode%

:demo
    Echo(Jobname %0 JobArgs: [%*]
Exit /b 0

:job
    Echo(Jobname %0 JobArgs: [%*]
    REM // demostrate return of errorlevel in ExitCode variable facilitate && || logic
    set /A ExitCode=%random% %% 2
Exit /b %ExitCode%
T3RR0R
  • 2,747
  • 3
  • 10
  • 25