Workspace files¶
Warning
This feature is part of the new incubating features. This means that it is under development, and looking for user testing and feedback. For more info see Incubating section.
Workspaces are defined by the conanws.yml
and/or conanws.py
files that will define the “root” workspace folder.
conanws.yml¶
The most basic implementation of a workspace is a conanws.yml
file. It defines the workspace’s packages
(editable packages).
For instance, a workspace conanws.yml
defining 2 packages
could be:
packages:
- path: dep1
ref: dep1/0.1
- path: dep2
ref: dep2/0.1
Moreover, it could not have the ref
field, and let Conan read the name/version from the respective path/conanfile.py:
packages:
- path: dep1
- path: dep2
conanws.py¶
A conanws.yml
can be extended with a way more powerful conanws.py
that follows the same relationship as
a ConanFile
does with its conandata.yml
. If we want to dynamically define the packages
, for example based
on the existence of some name.txt
and version.txt
files in folders, the packages could be defined in conanws.py
as:
import os
from conan import Workspace
class MyWorkspace(Workspace):
def packages(self):
result = []
for f in os.listdir(self.folder):
if os.path.isdir(os.path.join(self.folder, f)):
with open(os.path.join(self.folder, f, "name.txt")) as fname:
name = fname.read().strip()
with open(os.path.join(self.folder, f, "version.txt")) as fversion:
version = fversion.read().strip()
result.append({"path": f, "ref": f"{name}/{version}"})
return result
It is also possible to re-use the conanfile.py
logic in set_name()
and set_version()
methods, using the Workspace.load_conanfile()
helper:
import os
from conan import Workspace
class MyWorkspace(Workspace):
def packages(self):
result = []
for f in os.listdir(self.folder):
if os.path.isdir(os.path.join(self.folder, f)):
conanfile = self.load_conanfile(f)
result.append({"path": f, "ref": f"{conanfile.name}/{conanfile.version}"})
return result
conanws.py super-build options¶
A conanws.py
used for a super-build workspaces file can manage options in two different ways:
It can define its own
options
with the normalconanfile.py
syntax, so the generatedconan_toolchain.cmake
for the super-project uses those inputs.It can collect the options of the workspace’s packages with the
workspace_packages_options
and process them in any user-custom way.
super-project options
A conanws.py
must define the options for the super-build in the ConanFile
class, and use those options in the generate()
method, as it usually happens with conanfile.py
files, something like:
from conan import ConanFile, Workspace
class MyWs(ConanFile):
settings = "arch", "build_type"
options = {"myoption": [1, 2, 3]}
def generate(self):
self.output.info(f"Generating with my option {self.options.myoption}!!!!")
class Ws(Workspace):
def root_conanfile(self):
return MyWs
Then, options can be provided with the usual syntax, via profiles or command line:
$ conan workspace super-install -of=build -o "*:myoption=1"
> conanws.py base project Conanfile: Generating with my option 1!!!!
Note there can be overlap with the options
defined in the workspace packages, as for super-projects those options are simply ignored, and only the options of the super-project are taken into account to generate the conan_toolchain.cmake
. For example, the conanws.py
can define a shared
option if it is desired that the conan_toolchain.cmake
will correctly define BUILD_SHARED_LIBS
or not when defining something like -o "*:shared=True"
, as the workspace packages having the shared
option information is discarded when the workspace packages are collapsed in the dependency graph to model the super-project.
packages options
The second alternative is to collect the options
of the workspace packages that have been collapsed. Recall that in the final dependency graph, the workspace packages are no longer represented, as they are no longer individual packages but part as the current super-build. The way to access their options information is via the workspace_packages_options
, and that information can be used in the generate()
method to do any desired action at the super-build project level.
So let’s say that a workspace containing a dep/0.1
package that contains the standard shared
options defines the following super-build ConanFile
:
from conan import ConanFile, Workspace
class MyWs(ConanFile):
def generate(self):
for pkg, options in self.workspace_packages_options.items():
for k, v in options.items():
self.output.info(f"Generating with opt {pkg}:{k}={v}!!!!")
class Ws(Workspace):
def root_conanfile(self):
return MyWs
Then, when the workspace package options are defined, the workspace ConanFile
can collect them.
$ conan workspace super-install -of=build -o "*:shared=True"
> conanws.py base project Conanfile: Generating with opt dep/0.1:shared=True!!!!!!!!
Note
In practice it is the responsibility of the workspace creator to define what to do with the options, either by defining its own options or collecting the workspace packages ones. Note it is not possible to automatically map workspace packages options to the super-project, as options are defined per-package. Two different packages could have different shared=True
and shared=False
values. Also, very often, the effect on the generated toolchain files is custom and implemented in each package generate()
method. This effect is programmatic (not declarative), it would be extremely challenging to aggregate all these effects in a single toolchain.
See also
Read the Workspace tutorial section.