Building with UBT successfully still asks to rebuild modules when opening the .uproject

Hello everyone,

I have the following scenario:

I’m writing a python script that does the removal of the Binaries, Intermediate and Saved folders from the root of the project and the Binaries and Intermediate folders from any Plugin in the root of the project.

After these actions are executed, my script then cleans and builds the project using UBT.exe and it does so successfully. I’ve checked this against the logs provided by the UBT.

My problem is this: I know that the build was successful. I know that the plugins and the modules were built successful. Even so, whenever I open my .uproject files, it’ll still appear a popup that says there are missing modules that need to be rebuilt, and those are my core project and my plugins.

How can I fix this? What am I doing wrong?

Project name is “MenuSystem” and I have only 1 plugin called “MultiplayerSessions”

Here’s the python script:

import os
import shutil
import subprocess
import datetime

# Function to write to a log file
def log_message(message):
    with open("script_log.txt", "a") as log_file:
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_file.write(f"[{timestamp}] {message}\n")
        print(message)

def find_uproject_file():
    """Find a .uproject file in the current directory."""
    for file in os.listdir(os.getcwd()):
        if file.endswith(".uproject"):
            return file
    return None

def folder_exists(folder_path):
    """Check if a folder exists."""
    return os.path.exists(folder_path)

def delete_folder(folder_path):
    """Delete a folder if it exists."""
    if folder_exists(folder_path):
        shutil.rmtree(folder_path)
        log_message(f"Deleted folder: {folder_path}")

def check_folders_exist(folder_list):
    """Check if any folders in the given list exist."""
    return any(folder_exists(folder) for folder in folder_list)

def delete_plugin_folders(plugin_folder):
    """Delete specific folders in each plugin subfolder."""
    for plugin in os.listdir(plugin_folder):
        plugin_path = os.path.join(plugin_folder, plugin)
        if os.path.isdir(plugin_path):
            # Folders to delete in each plugin
            for folder_name in ["Binaries", "Intermediate"]:
                delete_folder(os.path.join(plugin_path, folder_name))

    """Generate Visual Studio project files for an Unreal Engine project."""
def generate_vs_project(uproject_path):
    cmd = 'UnrealVersionSelector.exe /projectfiles "' + uproject_path + '"'
    log_message("Running command: " + cmd)
    try:
        subprocess.run(cmd, check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        log_message("Generated Visual Studio project files.")
    except subprocess.CalledProcessError as e:
        log_message(f"Failed to generate Visual Studio project files: {e}")
        log_message("Error output: " + e.stderr.decode())

def clean_and_build_unreal_project(full_uproject_path, project_name, build_configuration="Development", platform="Win64"):
    """
    Rebuild the Unreal Engine project using UnrealBuildTool.
    :param full_uproject_path: Full path to the .uproject file.
    :param project_name: Name of the Unreal project (without .uproject extension).
    :param build_configuration: Build configuration (e.g., Development, Shipping).
    :param platform: Target platform (e.g., Win64, Win32).
    """
    # Command to clean and rebuild the project
    cmd_clean = f'UnrealBuildTool.exe -clean {project_name} {platform} {build_configuration} -project="{full_uproject_path}" -waitmutex'
    cmd_build = f'UnrealBuildTool.exe {project_name} {platform} {build_configuration} -project="{full_uproject_path}" -waitmutex'

    # Status 
    cmd_clean_status = False
    cmd_build_status = False
    
    # Run the clean command
    log_message("Running clean command: " + cmd_clean)
    try:
        subprocess.run(cmd_clean, check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        log_message("Successfully cleaned the Unreal Engine project.")
        cmd_clean_status = True
    except subprocess.CalledProcessError as e:
        log_message(f"Failed to clean Unreal Engine project: {e}")
        log_message("Error output: " + e.stderr.decode())

    # Run the build command
    log_message("Running build command: " + cmd_build)
    try:
        subprocess.run(cmd_build, check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        log_message("Successfully rebuilt the Unreal Engine project.")
        cmd_build_status = True
    except subprocess.CalledProcessError as e:
        log_message(f"Failed to rebuild Unreal Engine project: {e}")
        log_message("Error output: " + e.stderr.decode())

    return cmd_clean_status and cmd_build_status


def main():
    root_folders = [os.path.join(os.getcwd(), folder) for folder in ["Binaries", "Intermediate", "Saved"]]
    plugins_folder = os.path.join(os.getcwd(), "Plugins")

    # Check if root or plugin folders exist before deleting
    root_folders_exist = check_folders_exist(root_folders)
    plugins_folder_exist = os.path.exists(plugins_folder)

    # Delete root folders
    for folder in root_folders:
        delete_folder(folder)

    # Delete plugin folders
    if plugins_folder_exist:
        delete_plugin_folders(plugins_folder)

    # Generate VS project files
    # getting the full path of the .uproject file, if exists
    project_root_path = os.getcwd()
    uproject_file = find_uproject_file()

    if uproject_file:
        full_uproject_path = os.path.join(project_root_path, uproject_file)
        project_name = os.path.splitext(uproject_file)[0]
        log_message("Found .uproject file:" + uproject_file)
        log_message("Full path to .uproject file:" + full_uproject_path)
        log_message("Project name: " + project_name)
    else:
        print("No .uproject file found.")

    build_status = False

    if root_folders_exist or plugins_folder_exist:
        if os.path.exists(uproject_file):
            generate_vs_project(full_uproject_path)
            build_status = clean_and_build_unreal_project(full_uproject_path, project_name)
        else:
            log_message(f"{uproject_file} not found, skipping project generation.")

    log_message("Project cleaned and built with status: " + str(build_status))
    log_message("Script ended.")

if __name__ == "__main__":
    main()

The ending logs from UBT:

Building MenuSystem...
Using Visual Studio 2022 14.36.32543 toolchain (D:\Apps\Visual Studio\VC\Tools\MSVC\14.36.32532) and Windows 10.0.22621.0 SDK (C:\Program Files (x86)\Windows Kits\10).
Determining max actions to execute in parallel (8 physical cores, 16 logical cores)
  Executing up to 8 processes, one per physical core
Adding event matcher: CompileEventMatcher
Adding event matcher: LinkEventMatcher
Adding event matcher: MicrosoftEventMatcher
Adding event matcher: XoreaxEventMatcher
Distributing 19 actions to XGE
UnrealBuildTool Compile

--------------------Build System Warning---------------------------------------
License not activated:
    License is not activated. Please activate the license in the coordinator.
    This build will run in standalone mode.

-------------------------------------------------------------------------------
 
Build ID: {D4AF5367-04CD-4420-A4B6-350732802ADB}
 
--------------------Project: Default-------------------------------------------
[1/19] Copy tbb.pdb (0:00.17 at +0:00)
[2/19] Copy tbbmalloc.dll (0:00.15 at +0:00)
[3/19] Copy tbbmalloc.pdb (0:00.15 at +0:00)
[4/19] Copy tbb12.dll (0:00.15 at +0:00)
[5/19] Copy tbb.dll (0:00.18 at +0:00)
[6/19] Copy D3D12Core.dll (0:00.17 at +0:00)
[7/19] Copy d3d12SDKLayers.dll (0:00.17 at +0:00)
[8/19] Copy OpenImageDenoise.dll (0:00.17 at +0:00)
[9/19] Resource Default.rc2 (0:00.15 at +0:00)
[10/19] Compile [x64] SharedPCH.Engine.Cpp20.cpp (0:23.29 at +0:00)
[11/19] Compile [x64] MenuSystemGameMode.gen.cpp (0:04.23 at +0:23)
[12/19] Compile [x64] MenuSystemCharacter.gen.cpp (0:04.23 at +0:23)
[13/19] Compile [x64] MenuSystem.init.gen.cpp (0:04.46 at +0:23)
[14/19] Compile [x64] MenuSystemGameMode.cpp (0:04.60 at +0:23)
[15/19] Compile [x64] MenuSystem.cpp (0:04.68 at +0:23)
[16/19] Compile [x64] Module.MultiplayerSessions.cpp (0:04.82 at +0:23)
[17/19] Compile [x64] MenuSystemCharacter.cpp (0:04.92 at +0:23)
[18/19] Link [x64] MenuSystem.exe (0:07.70 at +0:28)
[19/19] WriteMetadata MenuSystem.target (0:00.28 at +0:35)
D:\Apps\Unreal Engine Projects\MenuSystem\Source\MenuSystem\MenuSystemCharacter.cpp(23): warning C5038: data member 'AMenuSystemCharacter::SessionSearch' will be initialized after data member 'AMenuSystemCharacter::CreateSessionCompleteDelegate'
   Creating library D:\Apps\Unreal Engine Projects\MenuSystem\Binaries\Win64\MenuSystem.lib and object D:\Apps\Unreal Engine Projects\MenuSystem\Binaries\Win64\MenuSystem.exp
---------------------- Done ----------------------
 
    Rebuild All: 1 succeeded, 0 failed, 0 skipped
 
1 build system warning(s):
   - License not activated
 
Total time in XGE executor: 36.47 seconds
Total execution time: 39.00 seconds
WriteFileIfChanged() wrote 52 changed files of 52 requested writes.
Timeline:

[ 0.000]
[ 0.000](+39.002) <unknown>
[39.002]

I’ve checked to see if maybe the plugin is somehow not included in the build command but as you can see in the UBT logs, it is.

Any input is much appreciated.

Thanks!