Skip to content

Editable in manifest mode#1868

Open
Ikar-Rahl wants to merge 2 commits intomicrosoft:mainfrom
Ikar-Rahl:ikar-rahl/editable_manifest
Open

Editable in manifest mode#1868
Ikar-Rahl wants to merge 2 commits intomicrosoft:mainfrom
Ikar-Rahl:ikar-rahl/editable_manifest

Conversation

@Ikar-Rahl
Copy link
Copy Markdown

Proposed Workflow ("Editable Mode")

I propose a formal "Editable" workflow integrated into Manifest Mode.

This is an ongoing draft of my initial experimentations and is not (yet) a functional proposal.

1. Setup

I am working on MyProj defined by vcpkg.json.

2. Materialization

I signal to vcpkg that zlib should be editable (via a command, environment variable, or configuration).

Expected outcome:

  • First, vcpkg automatically resolves the correct version of zlib based on the current manifest, fetches the source (preferably via git clone to preserve history, or source extraction), and places it in a local user-writable directory (e.g., ./vcpkg_edits/zlib).
  • Then, vcpkg automatically treats this new local directory as the source for the zlib port, effectively creating a temporary local overlay.

3. Iteration

  1. I modify the source in ./vcpkg_edits/zlib.
  2. I run the standard build command for MyProj (e.g., cmake --build .).

Crucial Change (The "Dirty Build"):

  • For the Port: Vcpkg detects this port is currently "Editable". Instead of the standard behavior (hash check -> clean -> rebuild -> repackage), it performs a Dirty Build (Incremental). It invokes the underlying build system (CMake, Ninja, Make) directly on the existing build artifacts in the editable directory.
  • For the Consumer: Simultaneously, the ABI hash of the editable port is updated (via a "dirty bit" or salted hash). This signals to the consumer (MyProj) that a dependency has changed, triggering a non-standard incremental build/re-link of the consumer project against the updated binary.

4. Completion

I validate my changes. I can then commit the changes (if git history was preserved or added) or generate a patch. I disable the editable state, and vcpkg returns to strict manifest compliance.

The Golden Rule: "Whatever happens in editable mode, stays in editable mode." No impact on CI, registry, shared code. Local only.

@Ikar-Rahl Ikar-Rahl changed the title Initial draft for editable in manifest mode Editable in manifest mode Nov 25, 2025
@Ikar-Rahl Ikar-Rahl marked this pull request as draft November 25, 2025 15:36
@Ikar-Rahl
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Adobe"

@Ikar-Rahl Ikar-Rahl force-pushed the ikar-rahl/editable_manifest branch from 2639150 to 1c5bfcc Compare January 13, 2026 16:18
@Ikar-Rahl Ikar-Rahl marked this pull request as ready for review January 13, 2026 16:19
@Ikar-Rahl
Copy link
Copy Markdown
Author

Ikar-Rahl commented Jan 13, 2026

Working Proof of Concept (POC)

Here is a working POC demonstrating the proposed workflow.
Sister PR in vcpkg repo: microsoft/vcpkg#49403

By adding the following to vcpkg-configuration.json:

"editable-ports": {
  "path": "editable-ports",
  "ports": [
    "libpng"
  ]
}

You get a directory in editable-ports/libpng that contains 3 subfolders:

  • The port itself: Used exactly like an overlay port.
  • Src dir: Currently supports vcpkg_from_git, vcpkg_from_github, and vcpkg_from_gitlab (restricted to ports with exactly one call to these functions).
  • Build dir: Similar structure to the one in buildtrees.

Internal Logic

We defined 3 new internal variables:

  • Editable: Is the current port being built editable?
  • Editable-Mode: Is the current vcpkg install process, globally, running in an editable mode? (This allows incremental build and install of downstream dependencies).
  • IncrementalInstall: Allows installing only updated files and removing deleted ones.

This is a POC to drive future discussions and enhancements, but it proves the feasibility of this approach and outlines what is needed.

Capabilities

  • Source Editing: Direct editing of port sources.
  • Content-Based ABI: ABI Hash is calculated based on the content of the src folder (disables cache uploading when in editable mode).
  • Incremental Builds: Skips configuration step (relying on the underlying build system to retrigger if needed) and performs incremental build/link.
  • Clean Package Dir: The internal package directory is fully cleaned before install (as some ports rely on it being empty).
  • Incremental Install: Updates vcpkg_installed based on file content changes.
  • Downstream propagation: Incremental build/link/install for all ports depending on the editable port.

Current Limitations

  • Dirty Install State: Building a port while having installed files from its previous version in the vcpkg_installed folder may cause issues with legacy CMake (2.x) or exotic generators. FIXED
  • Fetcher Support: Only vcpkg_from_git/github/gitlab are currently supported.
  • Single Source: Only 1 vcpkg_from_* call is supported; an error is thrown if a second is encountered. FIXED
  • Build System: Only vcpkg_cmake_configure is supported (no support for meson, etc., yet).
  • Source Updates: Modifications to the vcpkg_from_* arguments after the initial clone are ignored until the user deletes the src folder manually. (This behavior might be desirable).
  • Global Flag: Editable-Mode is currently a global flag that applies to all ports, not just those dependent on an editable port. FIXED
  • Testing: Not thoroughly tested; edge cases likely exist.

All of these cases can be enhanced, but the priority was to demonstrate that this is a viable technical direction.

@Ikar-Rahl
Copy link
Copy Markdown
Author

Updates

  • Wildcard Support: Added wildcard support for the editable-port field. Patterns like "boost-*" or "*" now work as expected.
  • Updated Schema: Reflects the new configuration options.
  • Staged Install Mechanism: Switched from keeping files in the vcpkg_installed folder to staging them in a temporary directory and restoring them with the correct timestamp if not updated. This allows a port to build with its files properly removed and unavailable during the build process, providing a much more robust approach.
  • Editable Subtree Scope: Switched from a global "Editable Mode" flag (which applied to all ports) to an "Editable Subtree" logic. The mode now applies only if a port is explicitly editable or has a direct/indirect dependency that is editable. This correctly limits the incremental build behavior to the affected downstream dependencies.
  • ABI Salting: The ABI hash is now salted on the initial editable run to ensure it does not reuse the previously installed non-editable port, forcing a proper initial rebuild.
  • General Cleanup: Multiple cleanups from previous iterations (though some artifacts may still remain).

This fixes the Dirty Install State and Global Flag point described before.

@Ikar-Rahl
Copy link
Copy Markdown
Author

Ikar-Rahl commented Jan 16, 2026

Updates

  • Added support for multi-source ports: sources/src1, sources/src2 etc. (Single Source limitation fixed)
  • Redirected package folder to the editable port (now it contain: port, sources, build and package).

Limitations left:

  • Fetcher Support: Only vcpkg_from_git/github/gitlab are currently supported. The rest still build though.
  • Build System: Only vcpkg_cmake_configure is supported (no support for meson, etc., yet). They other should still build though.
  • Source Updates: Modifications to the vcpkg_from_* arguments after the initial clone are ignored until the user deletes the src folder manually. This will be tackled next.
  • Testing: Not thoroughly tested; edge cases likely exist.

@Ikar-Rahl Ikar-Rahl force-pushed the ikar-rahl/editable_manifest branch from 98b36c4 to e5a163a Compare January 29, 2026 14:30
@Ikar-Rahl
Copy link
Copy Markdown
Author

Pushed a cleaned up version. Mostly tweaks and fixes.
This seems to us as a functional and stable version, tested on hundred of ports, but mostly on cmake and some pre-build binaries.

@Ikar-Rahl Ikar-Rahl force-pushed the ikar-rahl/editable_manifest branch from e5a163a to df961ff Compare February 17, 2026 13:46
@Ikar-Rahl Ikar-Rahl force-pushed the ikar-rahl/editable_manifest branch from df961ff to b1de47f Compare March 2, 2026 15:57
Karim Beniamna added 2 commits March 3, 2026 10:52
This commit modifies the install command to preserve timestamps of
unmodified files. This is useful to avoid useless rebuilds in the
consuming projects: before this change, all headers were touched even if
a single one was modified, and thus timstamp-based build systems ended
up recompile many files unnecessarily.

The change is implemented by stashing files into a temporary folder
instead of deleting them, installing as usual then comparing the content
of the newly installed files with the stashed ones. If the content is
identical, the timestamp of the new file is updated to match the stashed
one, behaving as-if the file was never replaced.

Doing it this way guarantees that ports are built with a clean install
tree.

Note that this commit removes the use of hard-links: when installing a
file as a hard-link, we end up with a timestamp in the install tree that
matches the original file, which can be much older. This leads to build
systems not being aware of modifications (see
microsoft#1899). With this commit,
files are always copied, thereby ensuring that they will get a "now"
timestamp on first install.
This commit introduces support for editing ports and sources (in
manifest mode).

The following changes were made:
 - add "editable-ports" field to vcpkg.json, to allow specifying a
   destination folder for the editable ports and the list of ports to
   edit.
 - when installing an editable port for the first time, copy the port to
   the editable ports folder, and use this (possibly modified) copy as
   an overlay port on subsequent runs.
 - disable binary caching for editable ports, to ensure they are always
   built from source and to avoid polluting the cache with possibly
   incorrect artifacts (and/or artifacts of intermediate builds that
   will never be reused).
 - when building an editable port, use a build directory inside the
   editable port folder.
 - for computing the ABI hash of an editable port, include the sources
   folder from the editable port folder, which will contain checked out
   sources. This ensure that the port and their dependencies will be
   rebuilt when sources are modified.
 - mark editable ports and their dependencies with a flag to indicate
   that they must be built incrementally (VCPKG_EDITABLE_SUBTREE).
 - forward editable information through cmake variables, for consumption
   by `vcpkg-from-git*` scripts and `vcpkg-cmake` ports.

In addition to those changes in `vcpkg-tool`, the feature also require
the following changes in `vcpkg`:
 - hook `vcpkg-from-git*` scripts to delegate the download to a separate
   script that will clone the repo instead of downloading an archive.
 - modify `vcpkg_cmake_configure` to do incremental builds of editable
   ports.
@Ikar-Rahl Ikar-Rahl force-pushed the ikar-rahl/editable_manifest branch from b1de47f to 1b7ab93 Compare March 3, 2026 09:58
@BillyONeal
Copy link
Copy Markdown
Member

BillyONeal commented Apr 3, 2026

Somewhat repeating what I said over email:

The big problem with this feature as presented is that we effectively are forced to rebuild the universe of dependencies with this, because things that are --editable don't have ABI hashes, and the ABI hash is how manifest mode avoids constant rebuilds of things.

In particular, just not blowing away the sources is insufficient to achieve the outcome you're going for here, due to the interaction between ports and the installed tree. The installed tree is a shared resource that is both an input and output of the build and install process. Ports don't expect to have the bits they install already be installed, and ports do not usually have dependencies wired up correctly for incremental builds. That is, given port A depends on B depends on C, which install include/A.h, include/B.h, and include/C.h, respectively, we can't safely build B under our current model without deleting installed/<triplet>/include/A.h and installed/<triplet>/include/B.h first, which breaks any ability to incrementally build A.

As we described over email if the feature as proposed can be made to work we would be happy with it in principle but we think a writeup of how that end to end scenario is supposed to work needs to happen before we should merge this part in isolation.

@Osyotr
Copy link
Copy Markdown
Contributor

Osyotr commented Apr 6, 2026

If I understand correctly, the main goal of this PR is to be able to create and test patches without triggering a world rebuild.
I think it's achievable now for most cmake-based and probably many other ports by building without cleaning buildtrees and running ninja/make/etc. directly from the build dir and manually deploying built artifacts.
For reliability, vcpkg could provide some scripts to recreate the environment it was running the build in.

@BillyONeal
Copy link
Copy Markdown
Member

I think it's achievable now for most cmake-based and probably many other ports by building without cleaning buildtrees and running ninja/make/etc. directly from the build dir and manually deploying built artifacts.

The problem is that most builds are not prepared for a previous version of themselves to already be installed. That is, when building zlib, the build system has to deal with "/usr/include/zlib.h" (being the one from the installed tree) and mylocalbuild/src/inc/zlib.h both being reachable. If you're lucky, #include <zlib.h> goes to the second one, but depending on how their build is configured, it might go to the first one making local --editable edits to mylocalbuild/src/inc/zlib.h do nothing.

For reliability, vcpkg could provide some scripts to recreate the environment it was running the build in.

We already have vcpkg env but I don't think that achieves the "editing my dependencies feels the same as editing my top level consumer" scenario that @Ikar-Rahl is trying to achieve here.

@Ikar-Rahl
Copy link
Copy Markdown
Author

Ikar-Rahl commented Apr 7, 2026

Hello

The big problem with this feature as presented is that we effectively are forced to rebuild the universe of dependencies with this, because things that are --editable don't have ABI hashes, and the ABI hash is how manifest mode avoids constant rebuilds of things.

This PR does not rebuild the universe. Editable ports have an ABI.

just not blowing away the sources is insufficient to achieve the outcome you're going for here

The outcome is achieved, this PR is used by our teams without major issue so far and it does everything we wanted it to do.

Ports don't expect to have the bits they install already be installed

That's why we stash the install tree of the port before installing it, no issue there. It does not break incremental ability as the timestamps are restored. We don't do it for it dependencies though, unsure how needed it is but can be added.

I understand that you may not have time to take a serious look at it, but most of our concerns were already covered, the implementation ... just works. There may be some caveats we did not think through, but we are already benefiting from the enhanced workflow in our daily work.

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented Apr 8, 2026

This PR does not rebuild the universe. Editable ports have an ABI.

AFAICT the actual topic is the universe of reverse dependencies, and editable ports not having an ABI hash.

  • Reverse dependencies are rebuilt when a package is changed. In vcpkg, changes in packages are tracled via ABI hashes which reflect the input files, triplet, and environment.
    https://learn.microsoft.com/en-us/vcpkg/reference/binarycaching#abi-hash
  • Artifacts from editable ports change through direct, untracked modificiations to the sources. These modifications cannot be reflected in the ABI hash. That's why editable mode is incompatible with "ABI" tracking in vcpkg, and an ABI hash cannot be assigned to the installation of an editable port.
  • Without a corresponding ABI hash, it is not possible to cache binary artifacts, and to determine ABI hashes for artifacts of reverse dependencies.
    Every "editable" change to e.g. zlib will have to rebuild everything which depends on it (e.g. down to Qt, OpenCV, ...), with binary caching disabled.

@Ikar-Rahl
Copy link
Copy Markdown
Author

Ikar-Rahl commented Apr 8, 2026

Artifacts from editable ports change through direct, untracked modificiations to the sources.

They are tracked. Commands.build.cpp 1532 : abi_tag_entries.emplace_back("editable_sources", "0");
Would be useless if it did not detect changes if the sources.

Without a corresponding ABI hash, it is not possible to cache binary artifacts, and to determine ABI hashes for artifacts of reverse dependencies.

We specifically do not want to have binary artifact for editable ports, as those would pollute the cache. So the caching is disabled on purpose.

Every "editable" change to e.g. zlib will have to rebuild everything which depends on it (e.g. down to Qt, OpenCV, ...), with binary caching disabled.

This is actually something wanted, if you edit zlib, you want to rebuild all zlib dependencies. And those are being correctly rebuild, incrementally, and also incrementally installed, preserving timestamps.

As far as we have seen, there is no unnecessary neither missing operations that is happening during the whole workflow.

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented Apr 9, 2026

Artifacts from editable ports change through direct, untracked modificiations to the sources.

They are tracked. Commands.build.cpp 1532 : abi_tag_entries.emplace_back("editable_sources", "0"); Would be useless if it did not detect changes if the sources.

The problem is that the ABI hash would need needs to consider the full set of sources to track modifications in editable mode.
This is not solved by putting an "editable" marker into the ABI hash.

@dg0yt
Copy link
Copy Markdown
Contributor

dg0yt commented Apr 9, 2026

So IIUC the new code block walks through the source dir (editable_sources_path / "sources") to track modifications to the sources and put that into the hash. This is significantly different from the the current approach in classic mode where vcpkg tool has little knowledge about actual source dirs.

@Ikar-Rahl
Copy link
Copy Markdown
Author

Yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants