bpproject2cpp converts pure Blueprint UE projects to C++ projects entirely from the command line.
- Pure Blueprint projects have no
Source/directory and no.slnfile - This skill automates the full workflow: create Source structure → update
.uproject→ generate.sln→ compile - No editor required — all operations are command-line via UnrealBuildTool
- Verified on UE 5.5 with real compilation
Use Cases
| Scenario | Trigger |
|---|---|
| Pure BP project needs C++ module | "Add C++ support to this blueprint project" |
| Generate/regenerate .sln | "Generate solution file" / "Regenerate project files" |
| Add a new C++ class | "Create a new Actor class called MyCharacter" |
| Add a plugin module reference | "Add a C++ module for MyPlugin" |
| Check project C++ setup | "Does this project have C++ support?" |
| Compile C++ module | "Build the project" |
Mandatory Constraints
- Always backup
.uprojectbefore modifying it. Restore on failure. - Verify engine path — check
EngineAssociationin.uprojectand resolve the engine root via registry or known paths. - Never open the editor — all operations via command line only.
- Use forward slashes in all path arguments passed to UnrealBuildTool.
- Read
.uprojectbefore any operation to check current state (existing modules, plugins, etc.). - Do NOT delete existing
Source/directories or.slnfiles without explicit user confirmation. - Target.cs must be in
Source/(top-level), NOT inSource/{ModuleName}/— UBT usesTopDirectoryOnlysearch for*.Target.cs. - Match engine settings — Read
Build.versionand inspect the engine's target-setting enums; use only values it supports. - Confirm upgrades — Compare
EngineAssociationwith the resolved engine version; explain the impact and obtain confirmation before changing it.
Critical: Correct Directory Structure
UE projects have a specific directory layout that UBT expects. Getting this wrong causes compilation failures.
{ProjectDir}/
├── Source/ ← UBT scans this dir for *.Target.cs (TopDirectoryOnly!)
│ ├── {ProjectName}.Target.cs ← MUST be here, NOT in Source/{ModuleName}/
│ ├── {ProjectName}Editor.Target.cs ← MUST be here
│ └── {ModuleName}/ ← Module source files
│ ├── {ModuleName}.Build.cs
│ ├── {ModuleName}.h ← Module header (REQUIRED for compilation)
│ └── {ModuleName}.cpp ← Module source (REQUIRED for compilation)
├── {ProjectName}.sln ← Generated by GenerateProjectFiles.bat
├── {ProjectName}.vcxproj ← Generated by GenerateProjectFiles.bat
└── {ProjectName}.uproject
Why Target.cs must be in Source/ (not Source/ModuleName/)
UBT's ProjectHasCode() function (in UnrealBuildTool/System/NativeProjects.cs) checks for *.Target.cs using SearchOption.TopDirectoryOnly on the Source/ directory. If Target.cs is in a subdirectory like Source/ModuleName/, UBT won't find it, will treat the project as "has no code", and will auto-generate temporary Target.cs files in Intermediate/Source/ — causing duplicate definition errors.
Why .h and .cpp are required
Without at least one C++ source file (.h + .cpp) in the module directory, UBT may still treat the project as "no code" or fail to compile. A valid UE module must have an IMPLEMENT_MODULE macro in a .cpp file.
Core Workflow
Step 1: Resolve Engine Path
Read the .uproject file's EngineAssociation field:
- If it's a GUID like
{B1861105-...}: query Windows registryHKCU\Software\Epic Games\Unreal Engine\Builds\{GUID}to get the engine root path. - If it's a version string like
"5.5": check default install location or registry. - If it starts with
/: it's a relative path from the project.
Step 2: Detect Current State
import os, json
uproject_path = "<PROJECT_ROOT>/MyProject.uproject"
project_dir = os.path.dirname(uproject_path)
project_name = os.path.splitext(os.path.basename(uproject_path))[0]
has_source = os.path.isdir(os.path.join(project_dir, "Source"))
has_sln = os.path.exists(os.path.join(project_dir, f"{project_name}.sln"))
with open(uproject_path, 'r', encoding='utf-8') as f:
uproject = json.load(f)
existing_modules = [m["Name"] for m in uproject.get("Modules", [])]
Step 3: Create Source Structure
Create files in two locations: Target.cs files in Source/, module files in Source/{ModuleName}/.
File: {ProjectDir}/Source/{ModuleName}/{ModuleName}.Build.cs
using UnrealBuildTool;
public class {ModuleName} : ModuleRules
{
public {ModuleName}(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore"
});
}
}
File: {ProjectDir}/Source/{ProjectName}.Target.cs (top-level Source/)
using UnrealBuildTool;
using System.Collections.Generic;
public class {ProjectName}Target : TargetRules
{
public {ProjectName}Target(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
// Set versioned build options only after checking this engine's supported values.
ExtraModuleNames.AddRange(new string[] { "{ModuleName}" });
}
}
File: {ProjectDir}/Source/{ProjectName}Editor.Target.cs (top-level Source/)
using UnrealBuildTool;
using System.Collections.Generic;
public class {ProjectName}EditorTarget : TargetRules
{
public {ProjectName}EditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
// Set versioned build options only after checking this engine's supported values.
ExtraModuleNames.AddRange(new string[] { "{ModuleName}" });
}
}
File: {ProjectDir}/Source/{ModuleName}/{ModuleName}.h — Module header (REQUIRED)
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
class F{ModuleName}Module : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
File: {ProjectDir}/Source/{ModuleName}/{ModuleName}.cpp — Module source (REQUIRED)
// Copyright Epic Games, Inc. All Rights Reserved.
#include "{ModuleName}.h"
#include "Modules/ModuleManager.h"
#define LOCTEXT_NAMESPACE "F{ModuleName}Module"
void F{ModuleName}Module::StartupModule()
{
// Module startup logic
}
void F{ModuleName}Module::ShutdownModule()
{
// Module shutdown logic
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(F{ModuleName}Module, {ModuleName})
Step 4: Update .uproject
Add the module entry to the Modules array:
import json
with open(uproject_path, 'r', encoding='utf-8') as f:
uproject = json.load(f)
modules = uproject.setdefault("Modules", [])
if module_name not in [m["Name"] for m in modules]:
modules.append({
"Name": module_name,
"Type": "Runtime",
"LoadingPhase": "Default"
})
with open(uproject_path, 'w', encoding='utf-8') as f:
json.dump(uproject, f, indent='\t', ensure_ascii=False)
f.write('\n')
Step 5: Clean Intermediate (Important for Existing Projects)
If the project previously had build artifacts, clean Intermediate/ and Binaries/ to avoid stale cache conflicts:
rd /s /q "{ProjectDir}\Intermediate" 2>nul
rd /s /q "{ProjectDir}\Binaries\Win64" 2>nul
Why: UBT caches compiled BuildRules assemblies and source copies in
Intermediate/Source/andIntermediate/Build/BuildRules/. Stale files cause duplicate definition errors (CS0101).
Step 6: Generate .sln
Call UnrealBuildTool:
{EngineRoot}/Engine/Build/BatchFiles/GenerateProjectFiles.bat -projectfiles -project="{ProjectPath}" -game -progress
Alternative using RunUAT:
{EngineRoot}/Engine/Build/BatchFiles/RunUAT.bat BuildTarget -projectfiles -project="{ProjectPath}" -game
Step 7: Compile
{EngineRoot}/Engine/Build/BatchFiles/Build.bat {ProjectName}Editor Win64 Development -Project="{ProjectPath}" -WaitMutex
Step 8: Verify Results
Check all expected files exist and compilation succeeded:
{ProjectDir}/Source/{ModuleName}/{ModuleName}.Build.cs✅{ProjectDir}/Source/{ModuleName}/{ModuleName}.h✅{ProjectDir}/Source/{ModuleName}/{ModuleName}.cpp✅{ProjectDir}/Source/{ProjectName}.Target.cs✅ (top-level){ProjectDir}/Source/{ProjectName}Editor.Target.cs✅ (top-level){ProjectDir}/{ProjectName}.sln✅.uprojectcontains the module inModules✅- Compilation output:
Result: Succeeded✅
File Templates
Adding a C++ Header (.h)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "{ClassName}.generated.h"
UCLASS()
class {MODULE_API_MACRO} A{ClassName} : public AActor
{
GENERATED_BODY()
public:
A{ClassName}();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
};
Adding a C++ Source (.cpp)
#include "{ClassName}.h"
A{ClassName}::A{ClassName}()
{
PrimaryActorTick.bCanEverTick = true;
}
void A{ClassName}::BeginPlay()
{
Super::BeginPlay();
}
void A{ClassName}::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
Note: The
MODULE_API_MACROis{PROJECTNAME}_APIfor game modules (e.g.,CROPOUT_API).
Common Build.cs Module Dependencies
| Module Name | When to Add |
|---|---|
Core |
Always |
CoreUObject |
Always |
Engine |
Always |
InputCore |
Always (input handling) |
EnhancedInput |
Using Enhanced Input system |
GameplayTasks |
Using Gameplay Task system |
AIModule |
AI / Behavior Trees |
Niagara |
Niagara VFX |
UMG |
UI widgets |
Slate, SlateCore |
Editor UI |
UnrealEd |
Editor utilities |
GameplayTags |
Gameplay tag system |
Error Handling
| Error | Cause | Fix |
|---|---|---|
CS0101: already contains a definition |
Stale Intermediate/Source/*.cs cache conflicts with new Source files |
Delete Intermediate/Source/ and Intermediate/Build/BuildRules/ |
has no code, but is being treated as a code-based project |
Target.cs in wrong location (e.g., Source/ModuleName/ instead of Source/) |
Move Target.cs to Source/ top-level |
| Target build-setting conflict | Target settings do not match the engine defaults | Inspect the engine's supported target-setting enums |
Source/ already exists |
Project already has C++ | Check existing modules, skip or warn |
EngineAssociation not found |
Custom/invalid engine path | Ask user for engine root |
GenerateProjectFiles.bat not found |
Wrong engine root | Re-resolve engine path |
| UBT fails with missing SDK | Platform SDK not installed | Add -platform=Win64 or install SDK |
| Compilation fails with no .h/.cpp | Module directory has no C++ source files | Create {ModuleName}.h and {ModuleName}.cpp with IMPLEMENT_MODULE |
Troubleshooting
"Cannot find GenerateProjectFiles.bat"
The engine path resolution failed. Verify:
- The GUID in
EngineAssociationexists in registry - The engine root directory actually exists
- Try:
reg query "HKCU\Software\Epic Games\Unreal Engine\Builds" /s
CS0101 Duplicate Definition Errors
Most common issue. UBT caches .cs files in Intermediate/Source/. When you add new Target.cs files, stale caches cause conflicts.
Fix: rd /s /q {Project}\Intermediate before generating or building.
"has no code" Warning
UBT creates temporary Target.cs in Intermediate/Source/ when it can't find real ones. This conflicts with manually created files.
Root cause: Target.cs must be at Source/*.Target.cs, not Source/ModuleName/*.Target.cs.
Build-Settings Warnings
Read Engine/Build/Build.version, then inspect the engine's target-setting enums and use only supported values.
Module Name Mismatch
The module name in Build.cs, Target.cs (ExtraModuleNames), and .uproject Modules array must all match exactly (case-sensitive).