IDEA-CMAKE - Abandoned CMake / Ninja / vcpkg Adoption Exploration¶
Abandoned historical idea. This is not an active implementation plan, not Release 1 scope, and not current branch direction. Operator decision on 2026-05-21 closed the linked backlog record as
WONT_DO. The supported build entrypoint remainspython -m emule_workspace. Archived sections below preserve migration wording from the original note; read them as provenance, not scheduled work.
Explored target stack: CMake 3.25+ · Ninja · MSVC cl.exe (v143) · vcpkg · VS Code Archived assumption: Windows-only, no VS IDE, no direct MSBuild workflow.
Table of Contents¶
- Overview & Goals
- Prerequisites & Tooling Setup
- Repository Structure After Migration
- Phase 1 — Dependency CMakeLists
- Phase 2 — vcpkg Integration
- Phase 3 — Root CMakeLists.txt
- Phase 4 — Main App CMakeLists.txt
- Phase 5 — Build & Configure Commands
- Phase 6 — VS Code Integration
- Killing the Old VS Files
- Known Pain Points & Gotchas
- Migration Checklist
1. Overview & Goals¶
Why migrate?¶
The current build system is a tangle of hand-rolled .cmd scripts, PowerShell workspace glue, MSBuild .vcxproj files, and per-dependency VS project wrappers (the zlib vcxproj is literally generated from a template at configure time). The result is:
- A full Visual Studio 2022 installation is required just to run
msbuild.exe. - Build output directories are deeply nested paths baked into vcxproj files with
$(Platform)\$(Configuration)path gymnastics. - Adding a new dependency means writing yet another wrapper project.
- No standard way for editors other than VS to understand the build graph.
CMake + Ninja + vcpkg gives:
- A single
cmake --buildcommand that works from any terminal with MSVC on PATH. compile_commands.jsongenerated by Ninja/CMake, understood by clangd, VS Code IntelliSense, and every modern C++ tooling.- vcpkg handles binary dependency resolution and caching.
- Presets encode the four canonical configurations (x64-debug, x64-release, x86-debug, x86-release) in a checked-in JSON file.
What changes¶
| Before | After |
|---|---|
emule.vcxproj |
eMule/srchybrid/CMakeLists.txt |
Per-dep wrapper .vcxproj files |
Per-dep CMakeLists.txt or add_subdirectory |
00-setup-and-build-release.cmd |
cmake --preset x64-release && cmake --build --preset x64-release |
$(CryptoPpRoot) property sheet variable |
vcpkg installed package, found via find_package(cryptopp) |
| Bison/Flex custom build steps | Removed — Parser.cpp / Scanner.cpp are pre-committed plain sources |
_SpecialBootstrapNodes config |
Dropped entirely |
| 46-DLL satellite i18n build | Out of scope, unchanged / done separately |
| VS IDE required | VS Build Tools only (no IDE needed) |
What stays the same¶
- Compiler:
cl.exe(MSVC v143), Windows SDK 10.0. - App type: Win32 GUI, static MFC, Unicode.
- Runtime:
/MTRelease,/MTdDebug. - Architectures: x86 (Win32) and x64.
- Configurations: Debug and Release.
- All source files, resource file (
emule.rc), manifests. Version.his still manually maintained — no git-driven version generation.Parser.cppandScanner.cppare plain committed source files.- MediaInfo is a runtime-loaded DLL — no build-time change needed.
2. Prerequisites & Tooling Setup¶
2.1 Visual Studio Build Tools (cl.exe without the IDE)¶
You do not need the full VS 2022 IDE. Install VS Build Tools 2022 with the following workloads:
winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--quiet --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 --includeRecommended"
This installs:
- cl.exe, link.exe, lib.exe (v143 toolset)
- Windows SDK 10.0
- MFC and ATL static libraries (the --includeRecommended flag pulls these in)
- vcvarsall.bat at C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat
Verify MFC is present. After install, confirm that the static MFC lib directory exists:
dir "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.xx.xxxxx\atlmfc\lib\x64\nafxcw.lib"
If it is missing, re-run the VS installer and add the component "C++ MFC for latest v143 build tools (x86 & x64)" (Microsoft.VisualStudio.Component.VC.MFC.ARM.Spectre is not what you want — look for Microsoft.VisualStudio.Component.VC.ATLMFC).
2.2 CMake 3.25+¶
winget install Kitware.CMake
Verify: cmake --version (must be >= 3.25.0).
CMake 3.25 is the minimum because:
- target_precompile_headers with MSVC-specific generator expressions was solidified.
- CMAKE_MSVC_RUNTIME_LIBRARY policy CMP0091 is set to NEW by default.
- MSVC_RUNTIME_LIBRARY target property works reliably.
2.3 Ninja¶
winget install Ninja-build.Ninja
Or install via Scoop: scoop install ninja
Verify: ninja --version (must be >= 1.11).
Why Ninja and not the "Visual Studio" CMake generator?
The Visual Studio generator produces .sln/.vcxproj files and delegates to MSBuild — the opposite of what we want. Ninja is a pure-dependency-graph executor that calls cl.exe directly. It also generates compile_commands.json when CMAKE_EXPORT_COMPILE_COMMANDS=ON.
2.4 vcpkg¶
# Choose a permanent home — NOT inside the repo
cd C:\tools
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat -disableMetrics
Set the environment variable (add to your user profile permanently):
[System.Environment]::SetEnvironmentVariable("VCPKG_ROOT", "C:\tools\vcpkg", "User")
You do not need to run vcpkg integrate install in the new CMake workflow — integration happens through the CMake toolchain file instead.
2.5 VS Code (optional but recommended)¶
winget install Microsoft.VisualStudioCode
code --install-extension ms-vscode.cpptools
code --install-extension ms-vscode.cmake-tools
code --install-extension twxs.cmake
2.6 Setting up the MSVC environment without the IDE¶
Every build command must be run from an MSVC-activated terminal. There are two ways:
Option A — Developer Command Prompt shortcut (interactive)
Start Menu → "Developer Command Prompt for VS 2022 Build Tools". This runs vcvarsall.bat x64 automatically.
Option B — Activate in any terminal (for scripts)
call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
Use x86 for 32-bit builds, x64 for 64-bit builds. You must call the matching architecture variant before configuring CMake — CMake captures the compiler at configure time and the architecture must match the target.
Option C — VS Code terminal integration
Set in .vscode/settings.json (see Phase 6). The CMake Tools extension can call vcvarsall.bat automatically when using a kit.
3. Repository Structure After Migration¶
The migration adds new CMakeLists.txt files and a vcpkg.json manifest. Nothing is moved or deleted from existing subdirectories (except the files listed in Section 10). The tree below shows only new/changed items.
C:\prj\p2p\eMule\eMulebb\emulebb-build\
├── CMakeLists.txt ← NEW: top-level root
├── CMakePresets.json ← NEW: 4 build presets
├── vcpkg.json ← NEW: vcpkg manifest
├── vcpkg-configuration.json ← NEW: vcpkg baseline pin
│
├── eMule/
│ └── srchybrid/
│ ├── CMakeLists.txt ← NEW: main app target
│ ├── emule.vcxproj ← KEEP (reference) then delete
│ ├── Stdafx.h / Stdafx.cpp ← unchanged
│ ├── Parser.cpp / Parser.y ← .cpp used as plain source
│ ├── Scanner.cpp / Scanner.l ← .cpp used as plain source
│ ├── emule.rc ← unchanged
│ └── res/
│ ├── emuleWin32.manifest ← unchanged
│ └── emulex64.manifest ← unchanged
│
├── emulebb-cryptopp/
│ └── (source tree, not built by CMake — vcpkg provides cryptopp)
│
├── emulebb-id3lib/
│ ├── CMakeLists.txt ← NEW: id3lib static lib target
│ └── (existing source tree unchanged)
│
├── emulebb-mbedtls/
│ └── CMakeLists.txt ← EXISTING upstream, used as-is
│
├── emulebb-miniupnp/
│ └── miniupnpc/
│ └── CMakeLists.txt ← EXISTING upstream, used as-is
│
├── emulebb-resizablelib/
│ └── ResizableLib/
│ └── CMakeLists.txt ← NEW: ResizableLib static lib target
│
└── emulebb-zlib/
└── CMakeLists.txt ← EXISTING upstream, used as-is
Key layout decisions:
- The root
CMakeLists.txtlives at the workspace root (eMulebb/), not inside theeMule/subfolder. This is so the root canadd_subdirectoryall sibling dependency trees. emulebb-cryptopp/source is kept for reference but not compiled by CMake — vcpkg'scryptopppackage replaces it entirely. You may archive or delete it after confirming the vcpkg build works.- vcpkg operates in manifest mode:
vcpkg.jsonat the root declares dependencies, vcpkg installs them intobuild/<preset>/vcpkg_installed/automatically during CMake configure.
4. Phase 1 — Dependency CMakeLists¶
4.1 zlib — use existing upstream CMakeLists¶
zlib already has a CMakeLists.txt. Add it as a subdirectory from the root. The only thing to control is disabling the shared library and the minizip addon:
# In root CMakeLists.txt (see Phase 3):
set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory(emulebb-zlib EXCLUDE_FROM_ALL)
# zlib's CMakeLists exports target "zlib" (static) or "zlibstatic" depending on version.
# Modern zlib (1.3+) always exports "zlibstatic" when BUILD_SHARED_LIBS=OFF.
# Alias for uniformity:
if(NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
endif()
Judgement call: We use add_subdirectory rather than FetchContent because the source is already vendored in the repo as emulebb-zlib/. FetchContent would re-download it at configure time, which is unnecessary and breaks offline builds.
4.2 mbedTLS — use existing upstream CMakeLists¶
mbedTLS upstream already has a CMakeLists.txt. Key options to set before add_subdirectory:
# In root CMakeLists.txt:
set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
set(USE_SHARED_MBEDTLS_LIBRARY OFF CACHE BOOL "" FORCE)
set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "" FORCE)
add_subdirectory(emulebb-mbedtls EXCLUDE_FROM_ALL)
# mbedTLS exports: MbedTLS::mbedtls, MbedTLS::mbedcrypto, MbedTLS::mbedx509
The MBEDTLS_ALLOW_PRIVATE_ACCESS preprocessor define is needed by the eMule app code (it accesses internal mbedTLS struct fields). This define must be set on the eMule app target, not on the mbedTLS library itself.
4.3 miniupnpc — use existing upstream CMakeLists¶
# In root CMakeLists.txt:
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_SAMPLE OFF CACHE BOOL "" FORCE)
set(NO_GETADDRINFO OFF CACHE BOOL "" FORCE)
add_subdirectory(emulebb-miniupnp/miniupnpc EXCLUDE_FROM_ALL)
# miniupnpc exports target "libminiupnpc-static"
The MINIUPNP_STATICLIB define is needed by code that includes miniupnpc headers. Set it on the eMule app target (and propagate it as a public define on the miniupnpc target if needed — see Phase 4.3 detail in Phase 7).
4.4 id3lib — write CMakeLists.txt from scratch¶
id3lib is not in vcpkg mainstream and its autoconf build system does not work on Windows. The existing emulebb-id3lib/libprj/id3lib.vcxproj reveals everything needed:
- Sources: all
.cppfiles in../src/(relative tolibprj/) - Include dirs:
.,..,../include,../include/id3, plus zlib headers - Defines:
_LIB,HAVE_CONFIG_H,ID3LIB_LINKOPTION=1 - Config header:
config.hmust come fromconfig.h.win32 - No PCH used in the library itself
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\emulebb-id3lib\CMakeLists.txt:
cmake_minimum_required(VERSION 3.25)
project(id3lib LANGUAGES CXX)
# id3lib needs zlib. It must already be in scope via the parent project.
# We accept either the upstream target name or our alias.
if(NOT TARGET ZLIB::ZLIB)
message(FATAL_ERROR "id3lib requires ZLIB::ZLIB target to be defined before add_subdirectory(emulebb-id3lib)")
endif()
add_library(id3lib STATIC
src/c_wrapper.cpp
src/field.cpp
src/field_binary.cpp
src/field_integer.cpp
src/field_string_ascii.cpp
src/field_string_unicode.cpp
src/frame.cpp
src/frame_impl.cpp
src/frame_parse.cpp
src/frame_render.cpp
src/globals.cpp
src/header.cpp
src/header_frame.cpp
src/header_tag.cpp
src/helpers.cpp
src/io.cpp
src/io_decorators.cpp
src/io_helpers.cpp
src/misc_support.cpp
src/mp3_parse.cpp
src/readers.cpp
src/spec.cpp
src/tag.cpp
src/tag_file.cpp
src/tag_find.cpp
src/tag_impl.cpp
src/tag_parse.cpp
src/tag_parse_lyrics3.cpp
src/tag_parse_musicmatch.cpp
src/tag_parse_v1.cpp
src/tag_render.cpp
src/utils.cpp
src/writer_decorators.cpp
src/writers.cpp
)
# The Windows config header lives at config.h.win32 in the root of the id3lib tree.
# We copy it to the build directory as "config.h" so #include "config.h" resolves.
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/config.h.win32"
"${CMAKE_CURRENT_BINARY_DIR}/config.h"
COPYONLY
)
target_include_directories(id3lib
PUBLIC
# Consumers need the public API headers
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/include/id3"
PRIVATE
# Internal includes
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
# config.h lives in the binary dir after configure_file above
"${CMAKE_CURRENT_BINARY_DIR}"
)
target_compile_definitions(id3lib
PUBLIC
ID3LIB_LINKOPTION=1
PRIVATE
_LIB
HAVE_CONFIG_H
# Suppress MSVC warnings about deprecated POSIX names and unsafe CRT
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE
# id3lib uses some old-style code that triggers these
_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
)
target_link_libraries(id3lib PRIVATE ZLIB::ZLIB)
# Inherit MSVC runtime from the project-wide setting (set by root CMakeLists)
set_target_properties(id3lib PROPERTIES
MSVC_RUNTIME_LIBRARY "${CMAKE_MSVC_RUNTIME_LIBRARY}"
)
Why configure_file instead of adding the source dir?
The id3lib source files do #include "config.h" (without any path prefix). Placing config.h.win32 as config.h in the build directory and adding that to the include path is the cleanest approach — it avoids polluting the source tree and works with out-of-source builds.
Why no PCH for id3lib? The original vcxproj does not use a PCH for this library. The sources are heterogeneous enough that a PCH would not save meaningful time, and it adds complexity.
4.5 ResizableLib — write CMakeLists.txt from scratch¶
ResizableLib is an MFC extension library. It uses StdAfx.h/StdAfx.cpp as its PCH. The original vcxproj uses UseOfMfc=Static for the configurations we care about.
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\emulebb-resizablelib\ResizableLib\CMakeLists.txt:
cmake_minimum_required(VERSION 3.25)
project(ResizableLib LANGUAGES CXX)
add_library(ResizableLib STATIC
ResizableComboBox.cpp
ResizableComboLBox.cpp
ResizableDialog.cpp
ResizableDialogEx.cpp
ResizableFormView.cpp
ResizableFrame.cpp
ResizableGrip.cpp
ResizableLayout.cpp
ResizableMDIChild.cpp
ResizableMDIFrame.cpp
ResizableMinMax.cpp
ResizableMsgSupport.cpp
ResizablePage.cpp
ResizablePageEx.cpp
ResizableSheet.cpp
ResizableSheetEx.cpp
ResizableSheetState.cpp
ResizableSplitterWnd.cpp
ResizableState.cpp
ResizableVersion.cpp
ResizableWndState.cpp
# StdAfx.cpp is the PCH creation unit — listed here and marked below
StdAfx.cpp
)
target_include_directories(ResizableLib
PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}"
)
target_compile_definitions(ResizableLib
PRIVATE
WIN32
_WINDOWS
UNICODE
_UNICODE
_CRT_SECURE_NO_WARNINGS
)
# Static MFC: tell MSVC to link against the static MFC libraries.
# This is done via the /MT or /MTd runtime selection plus the AFX static define.
# With CMake's MSVC_RUNTIME_LIBRARY mechanism, setting the runtime to
# MultiThreaded (no DLL) is sufficient — MFC picks up the right lib.
set_target_properties(ResizableLib PROPERTIES
MSVC_RUNTIME_LIBRARY "${CMAKE_MSVC_RUNTIME_LIBRARY}"
)
# PCH: StdAfx.h is the precompiled header, StdAfx.cpp creates it.
# CMake 3.16+ target_precompile_headers handles this correctly with MSVC.
target_precompile_headers(ResizableLib PRIVATE StdAfx.h)
# Mark StdAfx.cpp as the PCH creation unit. With MSVC, CMake generates /Yc
# on this file automatically when target_precompile_headers is used.
# No manual set_source_files_properties needed for the creation unit.
# All other .cpp files get /Yu (use PCH) automatically from target_precompile_headers.
# StdAfx.cpp gets /Yc automatically.
Important note on static MFC in a static library:
When ResizableLib is a static .lib that is linked into the eMule executable, the MFC linkage decision is made at the executable level, not the library level. The library just needs to be compiled with the right runtime (/MT or /MTd). The eMule executable's CMakeLists.txt sets USE_STATIC_MFC which pulls in the static MFC headers via afxwin.h. There is no separate /MD vs /MT negotiation needed for the .lib itself beyond matching the runtime.
5. Phase 2 — vcpkg Integration¶
5.1 Manifest mode¶
vcpkg operates in two modes: classic mode (global vcpkg install cryptopp) and manifest mode (vcpkg.json in the project root). We use manifest mode because:
- Dependencies are version-pinned and committed to the repo.
- Each preset can get its own installed directory (
build/<preset>/vcpkg_installed/). - No global vcpkg state pollution.
5.2 vcpkg.json¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\vcpkg.json:
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"name": "emule-broadband",
"version": "0.72",
"dependencies": [
{
"name": "cryptopp",
"features": []
}
]
}
Why only cryptopp?
- zlib, mbedTLS, miniupnpc: already vendored with their own CMakeLists — add_subdirectory is used.
- id3lib: not in vcpkg mainstream — custom CMakeLists written above.
- ResizableLib: not in vcpkg — custom CMakeLists written above.
- cryptopp: available in vcpkg as cryptopp, and the existing source tree in emulebb-cryptopp/ is a verbatim copy of the upstream anyway. vcpkg is the cleaner path.
5.3 vcpkg-configuration.json — baseline pin¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\vcpkg-configuration.json:
{
"default-registry": {
"kind": "git",
"baseline": "3508985146f1b1d248c67ead13f8f54be5b4f5da",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": []
}
Update the baseline: Run git -C %VCPKG_ROOT% rev-parse HEAD and paste the hash here. This pins all package versions to a specific vcpkg commit, ensuring reproducible builds. Bump this intentionally when you want dependency updates.
5.4 Triplets for x86 and x64 static¶
vcpkg triplets encode the target architecture and linkage. The relevant triplets are:
| CMake Preset | vcpkg Triplet |
|---|---|
| x64-release, x64-debug | x64-windows-static |
| x86-release, x86-debug | x86-windows-static |
The -static triplets build all vcpkg packages with /MT (static CRT). This matches our CMAKE_MSVC_RUNTIME_LIBRARY setting.
These triplets are set in CMakePresets.json (see Phase 6) via the CMake variable VCPKG_TARGET_TRIPLET.
5.5 How vcpkg integrates with CMake¶
The vcpkg toolchain file is passed to CMake via -DCMAKE_TOOLCHAIN_FILE. It:
- Sets up compiler detection to include vcpkg's installed headers.
- Provides
find_package()support for vcpkg packages. - Automatically installs missing packages when
VCPKG_MANIFEST_MODE=ON(the default whenvcpkg.jsonexists).
After CMake configure completes, vcpkg-installed headers are under:
build/<preset>/vcpkg_installed/<triplet>/include/
The cryptopp package exports a CMake target cryptopp::cryptopp via find_package(cryptopp CONFIG REQUIRED).
6. Phase 3 — Root CMakeLists.txt¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\CMakeLists.txt:
cmake_minimum_required(VERSION 3.25)
# ---------------------------------------------------------------------------
# Policy declarations — must come before project()
# ---------------------------------------------------------------------------
# CMP0091: MSVC_RUNTIME_LIBRARY abstraction. NEW = use the property.
cmake_policy(SET CMP0091 NEW)
# CMP0077: option() honours existing variables. Prevents dependencies from
# overriding our cache variables set before add_subdirectory.
cmake_policy(SET CMP0077 NEW)
project(eMuleBroadband
VERSION 0.72.0
LANGUAGES CXX RC
)
# ---------------------------------------------------------------------------
# Global settings
# ---------------------------------------------------------------------------
# Enforce C++17 across all targets
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Windows-only guard
if(NOT WIN32)
message(FATAL_ERROR "This project targets Windows only.")
endif()
# Generate compile_commands.json (used by clangd / VS Code IntelliSense)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# ---------------------------------------------------------------------------
# MSVC runtime library selection
# Use the abstract property rather than injecting /MT flags manually.
# CMP0091 NEW makes this work correctly.
# ---------------------------------------------------------------------------
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
set(CMAKE_MSVC_RUNTIME_LIBRARY
"MultiThreaded$<$<CONFIG:Debug>:Debug>"
CACHE STRING "MSVC runtime library selection" FORCE
)
endif()
# This expands to:
# Release → MultiThreaded → /MT
# Debug → MultiThreadedDebug → /MTd
# ---------------------------------------------------------------------------
# Output directories
# Keep binaries and libs in well-known locations within the build tree.
# ---------------------------------------------------------------------------
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
# ---------------------------------------------------------------------------
# vcpkg integration
# The toolchain file is passed in via -DCMAKE_TOOLCHAIN_FILE (set in presets).
# find_package for vcpkg packages becomes available automatically.
# ---------------------------------------------------------------------------
find_package(cryptopp CONFIG REQUIRED)
# ---------------------------------------------------------------------------
# zlib
# ---------------------------------------------------------------------------
set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory(emulebb-zlib EXCLUDE_FROM_ALL)
# Provide a canonical ZLIB::ZLIB alias regardless of zlib version
if(TARGET zlibstatic AND NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
elseif(TARGET zlib AND NOT TARGET ZLIB::ZLIB)
add_library(ZLIB::ZLIB ALIAS zlib)
endif()
# ---------------------------------------------------------------------------
# id3lib (custom CMakeLists written in Phase 1)
# Must come after zlib because id3lib links against ZLIB::ZLIB.
# ---------------------------------------------------------------------------
add_subdirectory(emulebb-id3lib EXCLUDE_FROM_ALL)
# ---------------------------------------------------------------------------
# mbedTLS
# ---------------------------------------------------------------------------
set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
set(USE_SHARED_MBEDTLS_LIBRARY OFF CACHE BOOL "" FORCE)
set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "" FORCE)
# Disable TF-PSA-Crypto subproject programs/tests as well
set(TF_PSA_CRYPTO_BUILD_TESTING OFF CACHE BOOL "" FORCE)
add_subdirectory(emulebb-mbedtls EXCLUDE_FROM_ALL)
# ---------------------------------------------------------------------------
# miniupnpc
# ---------------------------------------------------------------------------
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(UPNPC_BUILD_SAMPLE OFF CACHE BOOL "" FORCE)
set(UPNPC_NO_GETADDRINFO OFF CACHE BOOL "" FORCE)
add_subdirectory(emulebb-miniupnp/miniupnpc EXCLUDE_FROM_ALL)
# ---------------------------------------------------------------------------
# ResizableLib (custom CMakeLists written in Phase 1)
# ---------------------------------------------------------------------------
add_subdirectory(emulebb-resizablelib/ResizableLib EXCLUDE_FROM_ALL)
# ---------------------------------------------------------------------------
# Main application
# ---------------------------------------------------------------------------
add_subdirectory(eMule/srchybrid)
Why EXCLUDE_FROM_ALL?
This prevents dependency targets from showing up in the default cmake --build target unless they are actually needed by another target. Without it, a bare cmake --build would try to compile everything including test programs inside mbedTLS and miniupnpc (which we disabled above, but EXCLUDE_FROM_ALL is a second line of defence).
Why cmake_policy(SET CMP0077 NEW)?
Without this, option() calls inside dependency CMakeLists.txt can silently ignore the cache variables we set before add_subdirectory. With CMP0077 NEW, cache variables win.
7. Phase 4 — Main App CMakeLists.txt¶
7.1 Source file list: glob vs explicit¶
Decision: explicit list.
file(GLOB ...) is convenient but has a critical flaw: CMake does not re-run configure when you add or delete a source file in a globbed directory. You must manually re-run cmake --preset after adding a file, and it is easy to forget. With 247 source files that rarely change, an explicit list is more reliable and makes the build graph deterministic.
The explicit list is long but maintainable. It is organized by subsystem.
7.2 The full srchybrid/CMakeLists.txt¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\eMule\srchybrid\CMakeLists.txt:
cmake_minimum_required(VERSION 3.25)
# ---------------------------------------------------------------------------
# Source files — explicit list
# ---------------------------------------------------------------------------
set(EMULE_SOURCES
# Core / startup
Emule.cpp
EmuleDlg.cpp
Version.cpp
# File handling
AbstractFile.cpp
KnownFile.cpp
KnownFileList.cpp
PartFile.cpp
PartFileConvert.cpp
PartFileWriteThread.cpp
SharedFileList.cpp
ShareableFile.cpp
StatisticFile.cpp
CollectionFile.cpp
SafeFile.cpp
# Download system
DownloadQueue.cpp
DownloadClient.cpp
DownloadClientsCtrl.cpp
DownloadListCtrl.cpp
# Upload system
UploadQueue.cpp
UploadClient.cpp
UploadBandwidthThrottler.cpp
UploadDiskIOThread.cpp
UploadListCtrl.cpp
# Network / sockets
AsyncSocketEx.cpp
ClientUDPSocket.cpp
EMSocket.cpp
EncryptedDatagramSocket.cpp
EncryptedStreamSocket.cpp
HttpClientReqSocket.cpp
ListenSocket.cpp
ServerConnect.cpp
ServerSocket.cpp
UDPSocket.cpp
URLClient.cpp
WebSocket.cpp
BindAddressResolver.cpp
TLSthreading.cpp
# Server
Server.cpp
ServerList.cpp
ServerListCtrl.cpp
ServerWnd.cpp
# Clients / credits
BaseClient.cpp
ClientCredits.cpp
ClientList.cpp
ClientListCtrl.cpp
Friend.cpp
FriendList.cpp
FriendListCtrl.cpp
# Kademlia
kademlia/io/BufferedFileIO.cpp
kademlia/io/ByteIO.cpp
kademlia/io/DataIO.cpp
kademlia/io/FileIO.cpp
kademlia/io/IOException.cpp
kademlia/kademlia/Entry.cpp
kademlia/kademlia/Indexed.cpp
kademlia/kademlia/Kademlia.cpp
kademlia/kademlia/Prefs.cpp
kademlia/kademlia/Search.cpp
kademlia/kademlia/SearchManager.cpp
kademlia/kademlia/UDPFirewallTester.cpp
kademlia/net/KademliaUDPListener.cpp
kademlia/net/PacketTracking.cpp
kademlia/routing/Contact.cpp
kademlia/routing/RoutingBin.cpp
kademlia/routing/RoutingZone.cpp
kademlia/utils/LookupHistory.cpp
kademlia/utils/MiscUtils.cpp
kademlia/utils/ThreadName.cpp
kademlia/utils/UInt128.cpp
# Hashing / crypto
MD4.cpp
MD5Sum.cpp
SHA.cpp
SHAHashSet.cpp
AICHSyncThread.cpp
FileIdentifier.cpp
ClientCredits.cpp
CorruptionBlackBox.cpp
SelfTest.cpp
# Search
SearchDlg.cpp
SearchFile.cpp
SearchList.cpp
SearchListCtrl.cpp
SearchParamsWnd.cpp
SearchResultsWnd.cpp
ED2KLink.cpp
ED2kLinkDlg.cpp
# Bison/Flex generated — plain committed sources, NO generator step
Parser.cpp
Scanner.cpp
# Preferences / settings
Preferences.cpp
PreferencesDlg.cpp
PPgConnection.cpp
PPgDebug.cpp
PPgDirectories.cpp
PPgDisplay.cpp
PPgFiles.cpp
PPgGeneral.cpp
PPgIRC.cpp
PPgMessages.cpp
PPgNotify.cpp
PPgScheduler.cpp
PPgSecurity.cpp
PPgServer.cpp
PPgStats.cpp
PPgTweaks.cpp
PPgWebServer.cpp
Scheduler.cpp
Wizard.cpp
PShtWiz1.cpp
# Statistics / logging
Statistics.cpp
StatisticsDlg.cpp
StatisticsTree.cpp
Log.cpp
PerfLog.cpp
# UI — dialogs
AddFriend.cpp
AddSourceDlg.cpp
ArchivePreviewDlg.cpp
CatDialog.cpp
ChatSelector.cpp
ChatWnd.cpp
ClientDetailDialog.cpp
CollectionCreateDialog.cpp
CollectionListCtrl.cpp
CollectionViewDialog.cpp
CommentDialog.cpp
CommentDialogLst.cpp
CommentListCtrl.cpp
CreditsDlg.cpp
CreditsThread.cpp
DialogMinTrayBtn.cpp
DirectDownloadDlg.cpp
ExitBox.cpp
FileDetailDialog.cpp
FileDetailDialogInfo.cpp
FileDetailDialogName.cpp
FileDetailDlgStatistics.cpp
FileInfoDialog.cpp
HttpDownloadDlg.cpp
InputBox.cpp
IrcChannelListCtrl.cpp
IrcChannelTabCtrl.cpp
IrcMain.cpp
IrcNickListCtrl.cpp
IrcSocket.cpp
IrcWnd.cpp
KadContactHistogramCtrl.cpp
KadContactListCtrl.cpp
KadLookupGraph.cpp
KadSearchListCtrl.cpp
KademliaWnd.cpp
ListViewSearchDlg.cpp
ListViewWalkerPropertySheet.cpp
MetaDataDlg.cpp
MuleSystrayDlg.cpp
NetworkInfoDlg.cpp
PreviewDlg.cpp
QueueListCtrl.cpp
SMTPdialog.cpp
SendMail.cpp
SharedDirsTreeCtrl.cpp
SharedFilesCtrl.cpp
SharedFilesWnd.cpp
SmileySelector.cpp
TransferDlg.cpp
TransferWnd.cpp
TrayDialog.cpp
# UI — controls / widgets
3DPreviewControl.cpp
BarShader.cpp
BuddyButton.cpp
ButtonsTabCtrl.cpp
ClosableTabCtrl.cpp
ColorButton.cpp
ColourPopup.cpp
ComboBoxEx2.cpp
CustomAutoComplete.cpp
DirectoryTreeCtrl.cpp
DropDownButton.cpp
DropTarget.cpp
EditDelayed.cpp
EditX.cpp
EnBitmap.cpp
GDIThread.cpp
GradientStatic.cpp
HTRichEditCtrl.cpp
I18n.cpp
IconStatic.cpp
LayeredWindowHelperST.cpp
ListBoxST.cpp
ListCtrlEditable.cpp
ListCtrlX.cpp
MeterIcon.cpp
MuleListCtrl.cpp
MuleStatusBarCtrl.cpp
MuleToolBarCtrl.cpp
OScopeCtrl.cpp
ProgressCtrlX.cpp
Quantize.cpp
RichEditCtrlX.cpp
RichEditStream.cpp
SplitterControl.cpp
TabCtrl.cpp
TaskbarNotifier.cpp
TextToSpeech.cpp
TitledMenu.cpp
ToolBarCtrlX.cpp
ToolTipCtrlX.cpp
ToolbarWnd.cpp
TrayMenuBtn.cpp
TreeOptionsCtrl.cpp
TreeOptionsCtrlEx.cpp
TreePropSheet.cpp
TreePropSheetPgFrame.cpp
TreePropSheetPgFrameDef.cpp
# Media / preview
ArchiveRecovery.cpp
CaptchaGenerator.cpp
FrameGrabThread.cpp
GZipFile.cpp
IP2Country.cpp
IPFilter.cpp
IPFilterDlg.cpp
MediaInfo.cpp
MediaInfo_RIFF.cpp
MediaInfo_RealMedia.cpp
MediaInfo_WindowsMedia.cpp
Pinger.cpp
Preview.cpp
RARFile.cpp
ZIPFile.cpp
# Misc utilities
DeadSourceList.cpp
Ini2.cpp
Mdump.cpp
OtherFunctions.cpp
Packets.cpp
StringConversion.cpp
TimeTick.cpp
WebServer.cpp
UPnPImpl.cpp
UPnPImplMiniLib.cpp
UPnPImplWinServ.cpp
UPnPImplWrapper.cpp
# PCH creation unit — must be listed
Stdafx.cpp
# Resource
emule.rc
)
# ---------------------------------------------------------------------------
# Target definition
# ---------------------------------------------------------------------------
add_executable(emule WIN32 ${EMULE_SOURCES})
# ---------------------------------------------------------------------------
# Platform / architecture manifest selection
# WIN32 target → emuleWin32.manifest
# x64 target → emulex64.manifest
# The manifest is embedded by the linker via /MANIFEST:EMBED /MANIFESTINPUT:
# We control this through target_sources + set_source_files_properties, or
# alternatively through linker flags. We use linker flags (see below) to
# stay consistent with how the vcxproj worked.
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# Precompiled header
# ---------------------------------------------------------------------------
# target_precompile_headers tells CMake/MSVC:
# - Compile Stdafx.cpp with /Yc"Stdafx.h" (create PCH)
# - Compile all other sources with /Yu"Stdafx.h" (use PCH)
# The PCH file name becomes <target>.pch in the build dir.
# IMPORTANT: Stdafx.cpp must be in the source list (it is, above).
target_precompile_headers(emule PRIVATE Stdafx.h)
# ---------------------------------------------------------------------------
# Include directories
# ---------------------------------------------------------------------------
# Find the MSVC ATLMFC directory for MFC headers.
# When invoked from a vcvarsall-activated environment, the compiler knows
# where MFC lives. We still set it explicitly so CMake can show it in the
# compilation database.
cmake_path(GET CMAKE_CXX_COMPILER PARENT_PATH _msvc_bin_dir)
# Walk up from bin/<arch>/ to the MSVC toolset root
cmake_path(GET _msvc_bin_dir PARENT_PATH _msvc_hostarch_dir)
cmake_path(GET _msvc_hostarch_dir PARENT_PATH _msvc_tools_ver_dir)
cmake_path(GET _msvc_tools_ver_dir PARENT_PATH _msvc_tools_dir) # VC\Tools\MSVC
cmake_path(GET _msvc_tools_dir PARENT_PATH _vc_dir) # VC
set(_atlmfc_include "${_vc_dir}/../../Tools/MSVC/${CMAKE_VS_PLATFORM_TOOLSET_VERSION}/atlmfc/include")
# Fallback: use environment variable set by vcvarsall
if(NOT EXISTS "${_atlmfc_include}" AND DEFINED ENV{VCToolsInstallDir})
set(_atlmfc_include "$ENV{VCToolsInstallDir}/atlmfc/include")
endif()
target_include_directories(emule PRIVATE
# srchybrid itself (. and ..)
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/.."
# id3lib public headers
# (these come via the target link, but explicit here helps IntelliSense)
# mbedTLS, miniupnpc headers come via target_link_libraries below
# MFC / ATL headers — required for static MFC compilation
"${_atlmfc_include}"
)
# ---------------------------------------------------------------------------
# Compile definitions
# ---------------------------------------------------------------------------
target_compile_definitions(emule PRIVATE
# Project-specific
ID3LIB_LINKOPTION=1
MINIUPNP_STATICLIB
SUPPORT_LARGE_FILES
MBEDTLS_ALLOW_PRIVATE_ACCESS
# Windows targeting
WIN32
_WINDOWS
UNICODE
_UNICODE
WINVER=0x0601
_WIN32_WINNT=0x0601
WIN32_LEAN_AND_MEAN
# MFC static link: AFX_STATIC is not the right macro.
# For static MFC, we rely on the /MT runtime + the MFC lib selection
# which is driven by #pragma comment(lib, ...) inside afxwin.h.
# No additional define is needed beyond what the vcxproj had.
# Debug: inject _DEBUG (cl.exe does this automatically for /MTd,
# but being explicit avoids surprises with CMake generator expressions)
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG>
# Suppress legacy CRT warnings
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE
)
# ---------------------------------------------------------------------------
# Compiler flags
# ---------------------------------------------------------------------------
target_compile_options(emule PRIVATE
# All warnings
/W4
# Standards conformance
/Zc:throwingNew # STL assumption: operator new throws, never returns null
/Zc:inline # Remove unreferenced COMDAT
/utf-8 # Source and execution charset UTF-8
# x86 only: /safeseh (structured exception handler table)
$<$<STREQUAL:${CMAKE_GENERATOR_PLATFORM},Win32>:/safeseh>
# Release-only optimizations
$<$<CONFIG:Release>:/O2> # Maximize speed
$<$<CONFIG:Release>:/Oi> # Intrinsic functions
$<$<CONFIG:Release>:/Oy-> # Omit frame pointers (/Oy- = omit, counterintuitive)
# NOTE: /Oy- means "disable omit frame pointers" in MSVC.
# The vcxproj <OmitFramePointers>true</OmitFramePointers>
# maps to /Oy (no minus). Use /Oy here.
$<$<CONFIG:Release>:/Oy> # Correct flag for "omit frame pointers"
$<$<CONFIG:Release>:/GL> # Whole program optimization (enables LTCG)
$<$<CONFIG:Release>:/Gy> # Function-level linking (COMDAT)
# Debug
$<$<CONFIG:Debug>:/Od> # Disable optimization
$<$<CONFIG:Debug>:/Zi> # Full debug info
$<$<CONFIG:Debug>:/D _DEBUG> # Redundant with compile_definitions but harmless
)
# Remove the duplicate /Oy- — see note above. Only /Oy is needed.
# (The two lines above are intentionally left so the reader sees the correction inline.)
# ---------------------------------------------------------------------------
# Link libraries
# ---------------------------------------------------------------------------
target_link_libraries(emule PRIVATE
# Dependency targets from add_subdirectory
id3lib
ResizableLib
ZLIB::ZLIB
MbedTLS::mbedtls
MbedTLS::mbedcrypto
MbedTLS::mbedx509
libminiupnpc-static
# vcpkg cryptopp
cryptopp::cryptopp
# Windows SDK libraries
ADSIId.lib # ADSI (Active Directory) — used for auth
bcrypt.lib
crypt32.lib
delayimp.lib # Required for /DELAYLOAD linker flag
iphlpapi.lib
version.lib
winmm.lib
ws2_32.lib
)
# ---------------------------------------------------------------------------
# Linker flags
# ---------------------------------------------------------------------------
# Note: target_link_options appends flags. MSVC link.exe flags use / prefix.
# Delay-load DLLs — loaded on first use, not at process startup.
# /DELAYLOAD requires delayimp.lib (added above).
set(_delay_load_flags
/DELAYLOAD:gdiplus.dll
/DELAYLOAD:msimg32.dll
/DELAYLOAD:oleacc.dll
/DELAYLOAD:ws2_32.dll
)
# Ignore specific default libraries — these are pulled in by MFC/ATL headers
# on some SDK configurations but we don't want them.
set(_ignore_libs
/NODEFAULTLIB:mpr.lib
/NODEFAULTLIB:rasapi32.lib
/NODEFAULTLIB:secur32.lib
/NODEFAULTLIB:sensapi.lib
/NODEFAULTLIB:vfw32.lib
)
# Manifest embedding — embed the platform-specific manifest.
# The manifest file name is: emuleWin32.manifest (x86) or emulex64.manifest (x64).
# We use a generator expression to select the right file.
# /MANIFEST:EMBED embeds the manifest into the PE.
# /MANIFESTINPUT: provides additional manifest fragments to merge.
set(_manifest_file
"$<IF:$<STREQUAL:${CMAKE_GENERATOR_PLATFORM},Win32>,${CMAKE_CURRENT_SOURCE_DIR}/res/emuleWin32.manifest,${CMAKE_CURRENT_SOURCE_DIR}/res/emulex64.manifest>"
)
target_link_options(emule PRIVATE
${_delay_load_flags}
${_ignore_libs}
# Embed manifest
/MANIFEST:EMBED
/MANIFESTINPUT:${_manifest_file}
# Release: LTCG + COMDAT folding + reference optimization
$<$<CONFIG:Release>:/LTCG>
$<$<CONFIG:Release>:/OPT:ICF> # Identical COMDAT folding
$<$<CONFIG:Release>:/OPT:REF> # Remove unreferenced code/data
# Debug: no LTCG, keep all code
$<$<CONFIG:Debug>:/DEBUG:FULL>
$<$<CONFIG:Debug>:/OPT:NOICF>
$<$<CONFIG:Debug>:/OPT:NOREF>
# Windows subsystem (redundant with WIN32 keyword on add_executable but explicit)
/SUBSYSTEM:WINDOWS
)
# ---------------------------------------------------------------------------
# Static MFC linkage
# ---------------------------------------------------------------------------
# CMake does not have a built-in "use static MFC" switch for non-VS generators.
# When compiling with /MT(d), MFC's own headers use #pragma comment(lib, ...) to
# pull in the static MFC libraries (nafxcw.lib / nafxcwd.lib) automatically —
# provided the ATLMFC lib directory is on the library search path.
#
# vcvarsall.bat sets LIB to include the ATLMFC lib dir. In a Ninja build
# invoked from an activated prompt, this just works.
#
# The additional macro _AFXDLL must NOT be defined (that enables MFC DLL mode).
# Setting UNICODE and _UNICODE is sufficient.
#
# If you see linker errors about nafxcw.lib, add this:
# target_link_directories(emule PRIVATE "$ENV{VCToolsInstallDir}/atlmfc/lib/x64")
# (or x86 as appropriate — use a generator expression for arch)
target_link_directories(emule PRIVATE
"$<IF:$<STREQUAL:${CMAKE_GENERATOR_PLATFORM},Win32>,$ENV{VCToolsInstallDir}/atlmfc/lib/x86,$ENV{VCToolsInstallDir}/atlmfc/lib/x64>"
)
# ---------------------------------------------------------------------------
# MSVC runtime — already set globally in root CMakeLists.
# Set it explicitly on the target as well for belt-and-suspenders.
# ---------------------------------------------------------------------------
set_target_properties(emule PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
# ---------------------------------------------------------------------------
# Output name
# ---------------------------------------------------------------------------
set_target_properties(emule PROPERTIES
OUTPUT_NAME "emule"
PDB_NAME "emule"
)
Important correction on /Oy vs /Oy-:
In MSVC, /Oy means "omit frame pointers" and /Oy- means "do not omit frame pointers". The MSBuild <OmitFramePointers>true</OmitFramePointers> maps to /Oy. The target_compile_options block above has a note about this — remove the /Oy-> line and keep only $<$<CONFIG:Release>:/Oy>.
A note on WIN32 keyword on add_executable:
add_executable(emule WIN32 ...) passes /SUBSYSTEM:WINDOWS to the linker and sets WinMain as the entry point instead of main. This is what the vcxproj <SubSystem>Windows</SubSystem> did.
A note on the RC file:
Listing emule.rc in the source list is sufficient. CMake detects .rc files and compiles them with rc.exe automatically when the RC language is enabled in project(). The CMAKE_RC_FLAGS variable can be used to pass additional flags if needed (e.g., include paths for the RC compiler).
8. Phase 5 — Build & Configure Commands¶
All commands must be run from an MSVC-activated terminal (i.e., after vcvarsall.bat).
The working directory for all commands is C:\prj\p2p\eMule\eMulebb\emulebb-build\ (the workspace root where CMakeLists.txt and CMakePresets.json live).
8.1 First-time setup (run once)¶
rem Activate MSVC environment for x64 (needed for configure step)
call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
rem Set VCPKG_ROOT if not already in environment
set VCPKG_ROOT=C:\tools\vcpkg
cd C:\prj\p2p\eMule\eMulebb\emulebb-build
8.2 Configure — x64 Release¶
cmake --preset x64-release
This:
1. Reads CMakePresets.json, finds the x64-release preset.
2. Creates build/x64-release/.
3. Invokes vcpkg to install cryptopp into build/x64-release/vcpkg_installed/x64-windows-static/.
4. Runs cmake -G Ninja -A x64 -DCMAKE_BUILD_TYPE=Release ... internally.
5. Generates build/x64-release/build.ninja and build/x64-release/compile_commands.json.
Expected output (abbreviated):
-- Running vcpkg install
-- Installing: x64-windows-static cryptopp
-- Configuring done
-- Build files have been written to: C:/prj/p2p/eMulebb/build/x64-release
8.3 Build — x64 Release¶
cmake --build --preset x64-release
Or with a specific job count:
cmake --build --preset x64-release --parallel 8
Output binary: build/x64-release/bin/emule.exe
8.4 Configure — x64 Debug¶
call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
cmake --preset x64-debug
8.5 Build — x64 Debug¶
cmake --build --preset x64-debug
Output binary: build/x64-debug/bin/emule.exe
8.6 Configure — x86 Release¶
rem IMPORTANT: vcvarsall for x86, not x64
call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x86
cmake --preset x86-release
Why call vcvarsall.bat x86 for x86 builds?
CMake captures the compiler path at configure time. If you run vcvarsall x64 and then cmake --preset x86-release, you get a 64-bit compiler trying to target x86 cross-compilation. While MSVC supports cross-compilation (vcvarsall.bat amd64_x86), the simplest and most reliable approach is to activate the native x86 environment. The CMakePresets.json also sets CMAKE_GENERATOR_PLATFORM to Win32 which further guides the selection.
8.7 Build — x86 Release¶
cmake --build --preset x86-release
8.8 Incremental rebuild¶
CMake/Ninja automatically detects changed files. Just re-run the build command:
cmake --build --preset x64-release
Ninja will only recompile changed translation units.
8.9 Clean build¶
cmake --build --preset x64-release --target clean
Or delete the build directory entirely:
rmdir /s /q build\x64-release
cmake --preset x64-release
cmake --build --preset x64-release
8.10 Verbose build (to see exact cl.exe command lines)¶
cmake --build --preset x64-release --verbose
Or set VERBOSE=1:
set VERBOSE=1
cmake --build --preset x64-release
9. Phase 6 — VS Code Integration¶
9.1 CMakePresets.json¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\CMakePresets.json:
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 0
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"VCPKG_MANIFEST_MODE": "ON",
"VCPKG_MANIFEST_DIR": "${sourceDir}"
}
},
{
"name": "x64-debug",
"displayName": "x64 Debug",
"description": "64-bit Debug build with /MTd",
"inherits": "base",
"architecture": {
"value": "x64",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_GENERATOR_PLATFORM": "x64",
"VCPKG_TARGET_TRIPLET": "x64-windows-static",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDebug"
}
},
{
"name": "x64-release",
"displayName": "x64 Release",
"description": "64-bit Release build with /MT and LTO",
"inherits": "base",
"architecture": {
"value": "x64",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_GENERATOR_PLATFORM": "x64",
"VCPKG_TARGET_TRIPLET": "x64-windows-static",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded"
}
},
{
"name": "x86-debug",
"displayName": "x86 Debug",
"description": "32-bit Debug build with /MTd",
"inherits": "base",
"architecture": {
"value": "x86",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_GENERATOR_PLATFORM": "Win32",
"VCPKG_TARGET_TRIPLET": "x86-windows-static",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreadedDebug"
}
},
{
"name": "x86-release",
"displayName": "x86 Release",
"description": "32-bit Release build with /MT and LTO",
"inherits": "base",
"architecture": {
"value": "x86",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_GENERATOR_PLATFORM": "Win32",
"VCPKG_TARGET_TRIPLET": "x86-windows-static",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded"
}
}
],
"buildPresets": [
{
"name": "x64-debug",
"configurePreset": "x64-debug",
"displayName": "x64 Debug"
},
{
"name": "x64-release",
"configurePreset": "x64-release",
"displayName": "x64 Release"
},
{
"name": "x86-debug",
"configurePreset": "x86-debug",
"displayName": "x86 Debug"
},
{
"name": "x86-release",
"configurePreset": "x86-release",
"displayName": "x86 Release"
}
]
}
Notes on preset design:
"version": 6requires CMake 3.25+.toolchainFileuses$env{VCPKG_ROOT}which reads theVCPKG_ROOTenvironment variable. If the user has not set it, configure will fail with a clear error."strategy": "set"for architecture means CMake setsCMAKE_GENERATOR_PLATFORMfrom thearchitecturefield. This is necessary for Ninja, which does not use the VS generator's-Aflag mechanism.- Each preset gets its own
binaryDirvia${presetName}, so all four build trees coexist without interference.
9.2 VS Code settings¶
Create C:\prj\p2p\eMule\eMulebb\emulebb-build\.vscode\settings.json (or merge into existing):
{
"cmake.useCMakePresets": "always",
"cmake.defaultConfigurePreset": "x64-debug",
"cmake.defaultBuildPreset": "x64-debug",
"cmake.generator": "Ninja",
"cmake.buildDirectory": "${workspaceFolder}/build/${buildPreset}",
"cmake.sourceDirectory": "${workspaceFolder}",
"cmake.configureOnOpen": false,
"cmake.automaticReconfigure": false,
"cmake.exportCompileCommandsFile": true,
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/x64-debug/compile_commands.json",
"C_Cpp.intelliSenseEngine": "default",
"terminal.integrated.env.windows": {
"VCPKG_ROOT": "C:\\tools\\vcpkg"
},
"cmake.environment": {
"VCPKG_ROOT": "C:\\tools\\vcpkg"
}
}
Notes:
"cmake.useCMakePresets": "always"tells the CMake Tools extension to useCMakePresets.jsonexclusively rather than its own kit/variant system."cmake.configureOnOpen": falseprevents VS Code from silently configuring without the right MSVC environment activated. Manually trigger configure (Ctrl+Shift+P → CMake: Configure) after opening.C_Cpp.default.compileCommandspoints to the x64-debug compilation database for IntelliSense. Change this to whichever preset you use most.VCPKG_ROOTis set in bothterminal.integrated.env.windows(for terminal commands) andcmake.environment(for the CMake Tools extension's own invocations).
9.3 VS Code kit configuration¶
The CMake Tools extension uses "kits" to locate compilers. With CMakePresets.json and "useCMakePresets": "always", kits are less relevant — the toolchain file (vcpkg + MSVC) drives compiler detection. However, you should still select the Visual Studio Build Tools 2022 kit when prompted, so the extension knows where vcvarsall.bat is for activating the terminal.
In VS Code: Ctrl+Shift+P → CMake: Select a Kit → Visual Studio Build Tools 2022 Release - amd64
10. Killing the Old VS Files¶
10.1 Files to DELETE after migration is verified working¶
eMule/srchybrid/emule.vcxproj
eMule/srchybrid/emule.vcxproj.filters
eMule/srchybrid/emule.vcxproj.user (if present)
emulebb-cryptopp/cryptlib.vcxproj
emulebb-cryptopp/cryptlib.vcxproj.filters (if present)
emulebb-id3lib/libprj/id3lib.vcxproj
emulebb-id3lib/libprj/id3lib.vcxproj.filters (if present)
emulebb-id3lib/libprj/id3lib.sln
emulebb-resizablelib/ResizableLib/ResizableLib.vcxproj
emulebb-resizablelib/ResizableLib/ResizableLib.vcxproj.filters (if present)
templates/zlib/zlib.vcxproj (the generated template)
templates/mbedtls/mbedTLS.vcxproj (the generated template)
Also delete or archive the old build .cmd scripts and PowerShell workspace files once they are no longer needed:
00-setup-and-build-release.cmd
10-build-libs-release.cmd
11-build-libs-debug.cmd
20-build-emule-release.cmd
21-build-emule-debug.cmd
22-build-emule-release-incremental.cmd
23-build-emule-debug-incremental.cmd
24-build-emule-release-incremental-run-and-package.cmd
25-build-emule-debug-incremental-and-run.cmd
python -m emule_workspace
deps.json
scripts/ (all MSBuild/PS helper scripts)
helpers/ (review — some may be packaging helpers worth keeping)
10.2 Files to KEEP¶
eMule/srchybrid/Parser.y — keep for reference; generated Parser.cpp is the actual source
eMule/srchybrid/Scanner.l — keep for reference; generated Scanner.cpp is the actual source
eMule/srchybrid/Parser.cpp — KEEP: this is a committed plain source file
eMule/srchybrid/Parser.hpp — KEEP
eMule/srchybrid/Scanner.cpp — KEEP: this is a committed plain source file
eMule/srchybrid/Scanner.h — KEEP
eMule/srchybrid/Version.h — KEEP: manually maintained
eMule/srchybrid/emule.rc — KEEP
eMule/srchybrid/res/ — KEEP all .manifest, .ico, .bmp etc.
emulebb-id3lib/config.h.win32 — KEEP: used by the new CMakeLists via configure_file
10.3 .gitignore additions¶
Add to .gitignore (or create if absent at workspace root):
# CMake build trees
/build/
# vcpkg installed packages (inside build trees — already covered by /build/)
vcpkg_installed/
# CMake cache and generated files
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
*.ninja
*.ninja_deps
*.ninja_log
# VS Code local settings (machine-specific paths)
.vscode/settings.json.local
# Ninja build files
build.ninja
11. Known Pain Points & Gotchas¶
11.1 Static MFC with CMake — the most likely source of failures¶
CMake has no first-class "static MFC" concept outside of the Visual Studio generator. With Ninja + MSVC, there is no MSBuild magic to auto-link MFC. The mechanism that makes it work is:
#include <afxwin.h>(inStdafx.h) causes MSVC to emit#pragma comment(lib, "nafxcw.lib")(Release) or#pragma comment(lib, "nafxcwd.lib")(Debug).- These pragmas only work if the ATLMFC lib directory is on the linker's library search path (
LIBenvironment variable). vcvarsall.batsetsLIBto include$(VCToolsInstallDir)\atlmfc\lib\x64(or x86).- If you build from a non-activated terminal, you will get
LNK1104: cannot open file 'nafxcw.lib'.
The target_link_directories call in srchybrid/CMakeLists.txt provides a belt-and-suspenders fix by explicitly adding the ATLMFC lib path. However, it relies on VCToolsInstallDir being set — which vcvarsall.bat does.
Do not define _AFXDLL — that switches MFC to DLL mode, which is the opposite of what we want.
11.2 MSVC manifest embedding with Ninja¶
With the VS generator, manifest embedding is handled transparently by MSBuild's MT.exe invocation. With Ninja, you must pass /MANIFEST:EMBED and /MANIFESTINPUT:path explicitly as linker flags. The target_link_options in Phase 7 does this.
Caveat: The res/ directory has three manifests: emuleWin32.manifest, emulex64.manifest, and emuleARM64.manifest. The CMakePresets.json does not include an ARM64 preset (not in scope), so only the Win32 and x64 manifests are referenced in the generator expression. If ARM64 support is added later, a fifth preset and an ARM64 branch in the generator expression will be needed.
Caveat 2: CMake's add_executable(... WIN32 ...) generates a default manifest and embeds it automatically. When you also pass /MANIFESTINPUT:, the linker merges both manifests. To avoid manifest conflicts, you may need to disable CMake's automatic manifest generation:
set_target_properties(emule PROPERTIES
VS_DEBUGGER_WORKING_DIRECTORY "" # not relevant for Ninja
)
# Tell CMake not to generate its own default manifest:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:EMBED")
A more robust approach is to use set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1) and control manifest generation entirely through target_link_options. Test with sigcheck.exe -m emule.exe (Sysinternals) to verify the embedded manifest is correct.
11.3 Delay-load with Ninja/CMake¶
/DELAYLOAD:foo.dll must be accompanied by delayimp.lib in the link libraries. This is correctly handled in the target_link_libraries call. The flag syntax for target_link_options uses the forward-slash form (/DELAYLOAD:...) which is correct for link.exe.
A subtle issue: if ws2_32.lib is both delay-loaded (/DELAYLOAD:ws2_32.dll) AND listed in target_link_libraries (it is), the linker imports the stub __delayLoadHelper2 from delayimp.lib and the actual DLL is loaded lazily. This is intentional — the vcxproj had the same configuration. The ws2_32.lib in the link list provides the import library; the /DELAYLOAD flag replaces the immediate IAT entry with a lazy stub.
11.4 PCH with Ninja — filename collision¶
CMake's target_precompile_headers generates a PCH file named cmake_pch.hxx (or cmake_pch.h) in the build directory and creates a wrapper #include "cmake_pch.hxx" that also #includes the specified header. This means the actual PCH file is not named Stdafx.pch — it is named cmake_pch.hxx.pch or similar.
This is fine for the build — it is transparent. However, if any source file does #include "Stdafx.h" explicitly (which all 247 files likely do), that include is resolved from the source tree as normal. The PCH provides the pre-compiled version of Stdafx.h's content, but the explicit #include "Stdafx.h" in each source file is what triggers the /Yu"Stdafx.h" mechanism.
Verification: After configure, check build/x64-debug/CMakeFiles/emule.dir/flags.make (or the equivalent Ninja rule) to confirm /Yu"Stdafx.h" is present on non-PCH sources and /Yc"Stdafx.h" is on Stdafx.cpp.
Actually, target_precompile_headers with MSVC in CMake 3.16+ uses the specified header name directly with /Yu. No wrapper file is generated. The PCH output file lives in ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/<target>.dir/cmake_pch.hxx.pch. The Ninja rules will correctly use /Yu"Stdafx.h" because we passed Stdafx.h (not a path) to target_precompile_headers.
11.5 cryptopp AVX2 flags¶
The cryptopp package in vcpkg may compile certain source files with /arch:AVX2. If you are running on hardware without AVX2 (any pre-Haswell CPU), the resulting binary will crash at the first cryptographic operation with an "illegal instruction" exception.
The vcpkg x64-windows-static triplet compiles cryptopp with the upstream's own CPU detection code, which is generally safe (it uses CPUID to detect AVX2 at runtime and falls back). However, if you see crashes, rebuild vcpkg with a custom triplet that forces a safer instruction set:
Create C:\tools\vcpkg\triplets\custom\x64-windows-static-noavx2.cmake:
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_BUILD_TYPE release)
set(VCPKG_C_FLAGS "/arch:SSE2")
set(VCPKG_CXX_FLAGS "/arch:SSE2")
Then set VCPKG_TARGET_TRIPLET to custom-x64-windows-static-noavx2 in the affected preset.
11.6 id3lib quirks¶
- id3lib's source code predates modern C++ and uses
std::auto_ptr, deprecatedregisterkeyword, and other C++11-deprecated constructs. The_SILENCE_ALL_CXX17_DEPRECATION_WARNINGSdefine suppresses these. You may also need/wd4996to suppress deprecation warnings from MSVC itself. - id3lib uses
<zlib.h>internally. TheZLIB::ZLIBtarget must be available beforeadd_subdirectory(emulebb-id3lib). The rootCMakeLists.txtordersadd_subdirectory(emulebb-zlib)beforeadd_subdirectory(emulebb-id3lib)for this reason. config.hmust resolve at compile time. Theconfigure_fileapproach copiesconfig.h.win32→${CMAKE_CURRENT_BINARY_DIR}/config.h. ThePRIVATEinclude ofCMAKE_CURRENT_BINARY_DIRintarget_include_directoriesmakes this work.
11.7 miniupnpc MINIUPNP_STATICLIB propagation¶
The miniupnpc upstream CMakeLists.txt may or may not define MINIUPNP_STATICLIB as a public compile definition on libminiupnpc-static. Check the upstream CMakeLists after adding the subdirectory:
# Check if libminiupnpc-static propagates MINIUPNP_STATICLIB
grep -r "MINIUPNP_STATICLIB" emulebb-miniupnp/miniupnpc/CMakeLists.txt
If it does not, add it manually in the root CMakeLists.txt after add_subdirectory:
target_compile_definitions(libminiupnpc-static PUBLIC MINIUPNP_STATICLIB)
This ensures that when emule includes miniupnpc headers via #include "miniupnpc.h", the correct static-linkage ABI is used.
11.8 mbedTLS tf-psa-crypto subdirectory¶
Recent mbedTLS versions (3.5+) include a tf-psa-crypto/ subdirectory with its own CMakeLists. The eMule vcxproj includes headers from:
- $(MbedTlsRoot)include
- $(MbedTlsRoot)tf-psa-crypto\include
- $(MbedTlsRoot)tf-psa-crypto\drivers\builtin\include
The mbedTLS CMake build should expose these through the MbedTLS::mbedcrypto target's INTERFACE_INCLUDE_DIRECTORIES. If it does not, add them explicitly:
target_include_directories(emule PRIVATE
"${CMAKE_SOURCE_DIR}/emulebb-mbedtls/include"
"${CMAKE_SOURCE_DIR}/emulebb-mbedtls/tf-psa-crypto/include"
"${CMAKE_SOURCE_DIR}/emulebb-mbedtls/tf-psa-crypto/drivers/builtin/include"
)
11.9 zlib target name variance¶
Different versions of zlib's CMakeLists.txt export different target names:
- Older zlib (< 1.2.12): exports zlib (shared) and may not export zlibstatic at all.
- Modern zlib (>= 1.3): exports zlibstatic when BUILD_SHARED_LIBS=OFF.
The alias block in the root CMakeLists.txt handles both cases. If neither zlibstatic nor zlib exist as targets after add_subdirectory, zlib's CMakeLists has a non-standard structure — check the vendored version.
11.10 The _DEBUG define injection¶
The vcxproj has <AdditionalOptions>/D _DEBUG</AdditionalOptions> for Debug configurations. This is unusual — normally _DEBUG is set automatically by the CRT headers when /MTd is used. The explicit /D _DEBUG in the vcxproj is belt-and-suspenders. The target_compile_definitions in Phase 7 replicates this with $<$<CONFIG:Debug>:_DEBUG>.
11.11 /safeseh and x86¶
/safeseh (Safe Exception Handlers) is an x86-only linker flag. It has no effect on x64 (x64 uses a different SEH model). The generator expression $<$<STREQUAL:${CMAKE_GENERATOR_PLATFORM},Win32>:/safeseh> ensures it is only applied for 32-bit builds. Note: /safeseh applies to the assembler (for .asm files) and the linker. In this project it appears in <AdditionalOptions> which applies to the compiler — check whether it is actually needed or if it was a historical artifact. The flag is valid for cl.exe on x86 (it affects how the compiler generates SEH unwind tables).
12. Migration Checklist¶
Setup¶
- [ ] Install VS Build Tools 2022 with VC++ tools, Windows SDK 10.0, and MFC/ATL
- [ ] Verify
nafxcw.libexists in the ATLMFC lib directory - [ ] Install CMake 3.25+ (
winget install Kitware.CMake) - [ ] Install Ninja (
winget install Ninja-build.Ninja) - [ ] Clone vcpkg to
C:\tools\vcpkgand runbootstrap-vcpkg.bat - [ ] Set
VCPKG_ROOT=C:\tools\vcpkgas a permanent user environment variable - [ ] Install VS Code + CMake Tools + C/C++ extensions
Phase 1 — Dependency CMakeLists¶
- [ ] Create
emulebb-id3lib/CMakeLists.txt(Section 4.4) - [ ] Verify all 36 source files listed match the actual
emulebb-id3lib/src/directory - [ ] Verify
config.h.win32exists atemulebb-id3lib/config.h.win32 - [ ] Test standalone:
cmake -B build-id3lib-test -S emulebb-id3lib -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake - [ ] Create
emulebb-resizablelib/ResizableLib/CMakeLists.txt(Section 4.5) - [ ] Verify all
.cppfiles listed match the actual directory - [ ] Confirm
StdAfx.h/StdAfx.cppexist - [ ] Test standalone compile
Phase 2 — vcpkg¶
- [ ] Create
vcpkg.json(Section 5.2) - [ ] Create
vcpkg-configuration.jsonwith current vcpkg HEAD baseline (Section 5.3) - [ ] Run
%VCPKG_ROOT%\vcpkg install --triplet x64-windows-staticfrom the workspace root to test - [ ] Verify
cryptopp::cryptopptarget is found byfind_package(cryptopp CONFIG REQUIRED)
Phase 3 — Root CMakeLists.txt¶
- [ ] Create
CMakeLists.txtat workspace root (Section 6) - [ ] Verify
cmake_policy(SET CMP0091 NEW)andCMP0077 NEWare present beforeproject() - [ ] Verify
CMAKE_MSVC_RUNTIME_LIBRARYis set before anyadd_subdirectory - [ ] Test configure with just the dependencies (comment out the emule subdirectory) to catch errors early:
cmake --preset x64-debug - [ ] Confirm all dependency targets are created without errors
Phase 4 — Main App CMakeLists.txt¶
- [ ] Create
eMule/srchybrid/CMakeLists.txt(Section 7) - [ ] Cross-check source file list against
emule.vcxproj— ensure no files are missing - [ ] All 247
ClCompileentries accounted for - [ ]
kademlia/subdirectory sources use forward slashes in the CMake list - [ ]
Parser.cppandScanner.cppincluded as plain sources - [ ]
Stdafx.cppincluded (PCH creation unit) - [ ]
emule.rcincluded - [ ] Verify
target_precompile_headers(emule PRIVATE Stdafx.h)is present - [ ] Verify all four preprocessor defines are present:
ID3LIB_LINKOPTION=1,MINIUPNP_STATICLIB,SUPPORT_LARGE_FILES,MBEDTLS_ALLOW_PRIVATE_ACCESS - [ ] Verify all delay-load DLLs are listed:
gdiplus.dll,msimg32.dll,oleacc.dll,ws2_32.dll - [ ] Verify
delayimp.libis intarget_link_libraries - [ ] Verify ignore-default-lib entries:
mpr.lib,rasapi32.lib,secur32.lib,sensapi.lib,vfw32.lib - [ ] Verify
/GLand/LTCGare in Release compile/link options respectively - [ ] Verify manifest embedding flags for both x86 and x64
- [ ] Remove the erroneous
/Oy->line (keep only/Oyfor Release)
Phase 5 — Presets¶
- [ ] Create
CMakePresets.json(Section 9.1) - [ ] Verify
toolchainFileuses$env{VCPKG_ROOT} - [ ] Verify each preset has the correct
VCPKG_TARGET_TRIPLET - [ ] Verify
binaryDiris${sourceDir}/build/${presetName}
First Build¶
- [ ] Activate MSVC:
call vcvarsall.bat x64 - [ ] Configure:
cmake --preset x64-debug - [ ] vcpkg installs
cryptoppwithout errors - [ ] All CMake configure steps complete
- [ ] No "cannot find target" errors
- [ ] Build:
cmake --build --preset x64-debug - [ ] PCH compiles (
Stdafx.cppwith/Yc) - [ ] All source files compile with
/Yu - [ ] All dependency libraries link successfully
- [ ]
emule.exeis produced inbuild/x64-debug/bin/ - [ ] Test the binary: launch
emule.exe, confirm startup - [ ] Repeat for x64-release:
- [ ]
/GLappears in compile commands (verify with--verbose) - [ ]
/LTCGappears in link command - [ ]
emule.exeproduced inbuild/x64-release/bin/ - [ ] Repeat for x86-debug and x86-release (with
vcvarsall.bat x86)
VS Code¶
- [ ] Create
.vscode/settings.json(Section 9.2) - [ ] Open VS Code in workspace root
- [ ] CMake Tools extension detects
CMakePresets.json - [ ] Select kit: Visual Studio Build Tools 2022 Release - amd64
- [ ] Select configure preset: x64-debug
- [ ] Trigger configure (
Ctrl+Shift+P → CMake: Configure) - [ ] Verify IntelliSense uses
compile_commands.json(no red squiggles on MFC includes) - [ ] Trigger build from VS Code status bar
Cleanup¶
- [ ] Delete
emule.vcxprojand.vcxproj.filters - [ ] Delete
cryptlib.vcxproj - [ ] Delete
id3lib.vcxprojandid3lib.sln - [ ] Delete
ResizableLib.vcxproj - [ ] Delete generated template vcxproj files in
templates/ - [ ] Archive or delete old
.cmdbuild scripts - [ ] Add
build/to.gitignore - [ ] Update
README.mdwith new build instructions - [ ] Commit: new
CMakeLists.txtfiles,CMakePresets.json,vcpkg.json,vcpkg-configuration.json, updated.gitignore
End of migration plan.
Feature Identifier¶
PLAN_003: CMake Migration¶
This document describes the plan for migrating the eMulebb build system from Visual Studio .vcxproj/.sln files to CMake. This enables cross-IDE support, easier dependency management, and integration with modern CI/CD pipelines.
Status: Planning phase. The current build remains .vcxproj-based.