conan-io / conan-vs-extension

Conan Extension for Visual Studio
https://marketplace.visualstudio.com/items?itemName=conan-io.conan-vs-extension
MIT License
59 stars 34 forks source link

[Question] How to build a Visual Studio 2022 solution from a batch script? #249

Open Jeanmilost opened 3 months ago

Jeanmilost commented 3 months ago

I have a Visual Studio 2022 solution for which I need to write a completely automatized build script. The idea is to build the whole solution and get the binaries by simply double-clicking on a script file.

However I cannot find how to run the Conan build from my batch script. Based on the automatically generated conan_install.bat file, I tried to write the below script. But it is not working as expected, and it cause several issues, as e.g. the dependencies are not found while the solution is compiled although they were successfully built.

I can't think that a simple solution has not been implemented to achieve a such task. Can you please tell me how I can run correctly the Conan build for a Visual Studio 2022 solution from a batch script?

Below is the script I tried to implement:

:: --------------------------------------------------------------------------
:: Description: This batch script automates the process of managing Conan dependencies
::              for a Visual Studio project by checking if a rebuild of the Conan dependencies
::              is necessary and executing the Conan install command if changes are detected
:: Step-by-Step Breakdown:
::     1. Initialization
::        The script starts by enabling delayed variable expansion with SETLOCAL ENABLEDELAYEDEXPANSION,
::        which allows for dynamic updates to variables within loops and conditionals.
::        The current working directory is stored in CURRENT_DIR to allow restoration
::        later
::     2. Argument Handling
::        The script expects the paths to Conan and the target project folder
::        as the first two arguments (CONAN_PATH and TARGET_PATH). It then skips
::        these first two arguments for further processing
::     3. Conan Configuration Setup
::        If the .conan directory doesn't exist in the target path, it creates
::        the directory and copies predefined Conan build profiles (Debug_Win32,
::        Debug_x64, etc.) into it
::     4. Change Directory
::        The script changes the working directory to the target project folder
::        specified by TARGET_PATH
::     5. Check for Required Rebuild
::        The script initializes DO_REBUILD=0 to track whether a rebuild is necessary.
::        It checks for the existence of control files (CONANDATA_<CONFIG> and CONANFILE_<CONFIG>)
::        in the .conan directory. If these files don't exist, DO_REBUILD is set to 1.
::        The script compares conandata.yml and conanfile.py with their corresponding
::        files in .conan. If differences are found, DO_REBUILD is set to 1. If a .runconan
::        file exists, indicating changes in profiles, DO_REBUILD is set to 1, and the
::        .runconan file is deleted
::     6. Run Conan Install if Necessary
::        If DO_REBUILD is 1, the script extracts additional arguments for the Conan
::        install command, constructs the command, and runs conan install using the
::        specified arguments. If the Conan install succeeds, it updates the control
::        files in .conan to reflect the current state. If it fails, an error message
::        is displayed
::     7. Output and Exit
::        The script uses a helper function (OUTPUT_COLOR_TEXT) to display messages in
::        different colors depending on success or failure. The script concludes by restoring
::        the initial working directory and exiting with a success (EXIT_SUCCESS) or
::        failure (EXIT_FAILURE) status
:: Calling syntax:
::     - %1 Conan executable path
::     - %2 Target project path
::     - ... Conan parameters, e.g. . -pr:h=.conan/Debug_x64 -pr:b=default --build=missing 
:: --------------------------------------------------------------------------
@ECHO OFF

:: enable delayed environment variable expansion. This is important when working with loops
:: or conditional statements where the value of a variable within the same block of code
:: should be modified and accessed
SETLOCAL ENABLEDELAYEDEXPANSION

:: keep the current dir, will restore it at end
SET CURRENT_DIR=%CD%

:: get the Conan and target paths from passed arguments
SET CONAN_PATH=%~1
SET TARGET_PATH=%~2

:: skip the 2 first passed arguments, now they are kept locally
for /l %%i in (1,1,2) do SHIFT

SET DO_REBUILD=0

:: no .conan folder?
IF NOT EXIST "%TARGET_PATH%\.conan" (
        ECHO Create .conan folder and copy build profiles

        :: create the .conan folder
        MD "%TARGET_PATH%\.conan"

        :: copy the profiles files
        COPY /Y Profiles\Debug_Win32 %TARGET_PATH%\.conan\Debug_Win32
        COPY /Y Profiles\Debug_x64 %TARGET_PATH%\.conan\Debug_x64
        COPY /Y Profiles\Release_Win32 %TARGET_PATH%\.conan\Release_Win32
        COPY /Y Profiles\Release_x64 %TARGET_PATH%\.conan\Release_x64

        SET DO_REBUILD=1
    ) ELSE (
        :: check if debug win32 profile was modified
        FC "Profiles\Debug_Win32" "%TARGET_PATH%\.conan\Debug_Win32" > nul

        :: modified?
        IF ERRORLEVEL 1 (
                ECHO Debug Win32 profile was modified, update it
                COPY /Y Profiles\Debug_Win32 %TARGET_PATH%\.conan\Debug_Win32
                SET DO_REBUILD=1
            )

        :: check if debug x64 profile was modified
        FC "Profiles\Debug_x64" "%TARGET_PATH%\.conan\Debug_x64" > nul

        :: modified?
        IF ERRORLEVEL 1 (
                ECHO Debug x64 profile was modified, update it
                COPY /Y Profiles\Debug_x64 %TARGET_PATH%\.conan\Debug_x64
                SET DO_REBUILD=1
            )

        :: check if release win32 profile was modified
        FC "Profiles\Release_Win32" "%TARGET_PATH%\.conan\Release_Win32" > nul

        :: modified?
        IF ERRORLEVEL 1 (
                ECHO Release Win32 profile was modified, update it
                COPY /Y Profiles\Release_Win32 %TARGET_PATH%\.conan\Release_Win32
                SET DO_REBUILD=1
            )

        :: check if release x64 profile was modified
        FC "Profiles\Release_x64" "%TARGET_PATH%\.conan\Release_x64" > nul

        :: modified?
        IF ERRORLEVEL 1 (
                ECHO Release x64 profile was modified, update it
                COPY /Y Profiles\Release_x64 %TARGET_PATH%\.conan\Release_x64
                SET DO_REBUILD=1
            )
    )

:: change to project folder for which the Conan dependencies should be built
CD %TARGET_PATH%

:: check if the control files exist
IF NOT EXIST ".conan\CONANDATA_%CONAN_BUILD_CONFIG%" SET "DO_REBUILD=1"
IF NOT EXIST ".conan\CONANFILE_%CONAN_BUILD_CONFIG%" SET "DO_REBUILD=1"

:: check for changes in conandata.yml
IF EXIST ".conan\CONANDATA_%CONAN_BUILD_CONFIG%" (
        ECHO Checking changes in conandata.yml
        FC "conandata.yml" ".conan\CONANDATA_%CONAN_BUILD_CONFIG%" > nul

        IF ERRORLEVEL 1 (
                SET DO_REBUILD=1
                ECHO Changes detected in conandata.yml
            )
    )

:: check for changes in conanfile.py
IF EXIST ".conan\CONANFILE_%CONAN_BUILD_CONFIG%" (
        ECHO Checking changes in conanfile.py
        FC "conanfile.py" ".conan\CONANFILE_%CONAN_BUILD_CONFIG%" > nul

        IF ERRORLEVEL 1 (
                SET DO_REBUILD=1
                ECHO Changes detected in conanfile.py
            )
    )

:: if exists, the .runconan file indicates changes in profiles
IF EXIST ".conan\.runconan" (
        ECHO Changes in profiles detected
        SET DO_REBUILD=1
        DEL ".conan\.runconan"
    )

:: do rebuild the Conan dependencies?
IF %DO_REBUILD% EQU 1 (
        ECHO Changes detected, executing conan install...

        SET "args="

        :: extract arguments from received parameters
        :ARGS_LOOP
        IF "%~1"=="" GOTO after_args_loop
        SET "args=!args! %1"
        SHIFT
        GOTO ARGS_LOOP

        :AFTER_ARGS_LOOP
        ECHO Arguments for conan install: !args!

        :: build Conan dependencies
        "%CONAN_PATH%\conan.exe" install !args!

        :: succeeded?
        IF !ERRORLEVEL! NEQ 0 (
                CALL :FAILURE "Conan installation failed. Please check the console output to troubleshoot issues."
                GOTO EXIT_FAILURE
            )

        :: update control files to reflect current state
        COPY /Y conandata.yml .conan\CONANDATA_%CONAN_BUILD_CONFIG%
        COPY /Y conanfile.py .conan\CONANFILE_%CONAN_BUILD_CONFIG%

        CALL :SUCCESS "Conan installation completed successfully."
        GOTO EXIT_SUCCESS
    )

CALL :SUCCESS "No changes detected, skipping conan install..."
GOTO EXIT_SUCCESS

:: --------------------------------------------------------------------------
:: ***
:: * Output a colored text in the console
:: * @param {enum} %1 - color name
:: * @param {string} %2 - text to write to ouptut
:: **
:OUTPUT_COLOR_TEXT
%Windir%\System32\WindowsPowerShell\v1.0\Powershell.exe write-host -foregroundcolor %1 %2
GOTO :EOF
:: --------------------------------------------------------------------------
:: ***
:: * Called on failure
:: * @param {string} %1 - error message
:: **
:FAILURE
:: carriage return
ECHO 

CALL :OUTPUT_COLOR_TEXT Red %1

GOTO :EOF
:: --------------------------------------------------------------------------
:: ***
:: * Called on success
:: * @param {string} %1 - success message
:: **
:SUCCESS
:: carriage return
ECHO 

CALL :OUTPUT_COLOR_TEXT Green %1

GOTO :EOF
:: --------------------------------------------------------------------------
:: ***
:: * Called when script should exit with failure
:: **
:EXIT_FAILURE

:: restore initial folder
CD %CURRENT_DIR%

ENDLOCAL
EXIT /b 1

GOTO END
:: --------------------------------------------------------------------------
:: ***
:: * Called when script should exit with success
:: **
:EXIT_SUCCESS

:: restore initial folder
CD %CURRENT_DIR%

ENDLOCAL
EXIT /b 0
:: --------------------------------------------------------------------------
:: ***
:: * Called when script should end
:: **
:END
:: --------------------------------------------------------------------------
czoido commented 3 months ago

Hi @Jeanmilost,

Thanks a lot for your question.

I can't think that a simple solution has not been implemented to achieve a such task. Can you please tell me how I can run correctly the Conan build for a Visual Studio 2022 solution from a batch script?

If I understand correctly you are using the Conan Visual Studio Extension and modified the generated conan_install.bat? We would need a bit more data to know what could be happening, like the project structure, the conan log output... Is the conandeps property file generated? Can you see that added in the properties manager?

Jeanmilost commented 3 months ago

Hello @czoido, thank you for your answer.

What I want to do is the following:

To summarize, I want to know if there is a command line like: conan_extension.exe /rebuild:mySolution.sln

Or if not, either to add, if possible, a such command in the extension, or if not, to explain me how to write such script, with the minimum possible of operations?

czoido commented 3 months ago

Hi @Jeanmilost,

The only thing I can think of that is similar to what you want to achieve is to use the local developer flow on your project. Maybe you can try as an starting point with the msbuild_exe template:

conan new msbuild_exe -d name="myproject" -d version=1.0

then do something like:

conan install .
conan build .

Is this something similar yo what you want to use? You can modify the conanfile.py generated by the plugin to have a build method that you can call to build your project like the one that the template generates.