Skip to content

Q# External Dependencies (Libraries)

Alex Hansen edited this page Aug 20, 2024 · 7 revisions

Including an External Project

There are two ways to take a dependency on an external Q# project. The first is a local dependency, and the second is a GitHub dependency. The easiest way to add a dependency is to use the Add Q# project reference command from the VS Code command palette with a qsharp.json manifest file open. (It is also available as a right-click context menu on qsharp.json files).

To add a dependency manually, add a "dependencies" property to your qsharp.json project manifest file. A local dependency looks like this:

{
  "author": "your name here",
  "license": "your chosen license here",
  "dependencies": {
    "SomeDependency": {
      "path": "/path/to/other/project/on/disk"
    }
  }
}

And a GitHub dependency looks like this:

{
  "author": "your name here",
  "license": "your chosen license here",
  "dependencies": {
    "SomeDependency": {
      "github": {
        "owner": "GitHubUser",
        "repo": "GitHubRepoName",
        "ref": "CommitHash"
      }
    }
  }
}

Note: for GitHub dependencies, the ref property refers to a Github refspec, however we recommend always using a commit hash.

If the GitHub dependency is in a subdirectory of the repository, an optional "path" property can be used to specify that subdirectory:

{
  "author": "your name here",
  "license": "your chosen license here",
  "dependencies": {
    "SomeDependency": {
      "github": {
        "owner": "GitHubUser",
        "repo": "GitHubRepoName",
        "ref": "CommitHash",
        "path": "/path/to/dependency"
      }
    }
  }
}

Accessing an External Project

After following the steps in the above section, you'll be able to access items that have been exported from the external project. They'll be available in a namespace defined as the name given to the dependency in the qsharp.json project manifest file. As an example, consider the following manifest file:

{
  "author": "your name here",
  "license": "your chosen license here",
  "dependencies": {
    "SomeDependency": {
      "path": "/path/to/other/project/on/disk"
    }
  }
}

In this manifest file, we define an external dependency called "SomeDependency". This external project will therefore show up under the namespace SomeDependency. To access an exported callable Bar() from "SomeDependency", we can call it as such: SomeDependency.Bar();. To import all items from an external project, we can use a glob import: import SomeDependency.*;. This is analogous to the existing open syntax: open SomeDependency;.

Import Statements

Import statements allow for either importing individual items, or glob-importing entire namespaces into the current scope. Imports can also be used to alias items. Here are a few examples:

  • import Foo.Bar;: imports a single item called Bar from the namespace Foo.
  • import Foo.Bar as Foobar;: imports a single item called Bar from the namespace Foo, but makes it accessible in the local scope as Foobar.
  • import Foo.*;: import all items from the namespace Foo.
  • import Foo as F; import the namespace Foo as F, items inside Foo are now accessible via F. For example, Foo.Bar is now accessible as F.Bar.
  • import Foo.Bar, Foo as F, Foo.Bar as Foobar;: imports can be combined into one line.

Defining Your Project's API

Q# Projects are a great way to import external code. But what if you want to publish your project as a library, so others can import it? What if you want to become a Q# library author? A set of features has been added to enable you to define your project's exported API.

Export Statements

Any callable, type, or namespace can be exported for external usage. Consider the following Q# project structure:

.
├── qsharp.json
└── src/
    └──  MathStuff.qs

Any files included in the project must be listed in the qsharp.json file under "files", so the above project's manifest file should look like this:

{
  "author": "your name here",
  "license": "your chosen license here",
  "files": [ "src/MathStuff.qs" ]
}

In the QDK VS Code extension, a command exists to automatically populate "files". With the qsharp.json manifest file open in the editor, access the VS Code command palette menu and run Q#: populate qsharp.json files list. (You can also right click on a qsharp.json file and the command is on the context menu).

Now, consider the contents of MathStuff.qs:

function Add(a: Int, b: Int): Int {
  return a + b;
}

To export Add, we add an export statement:

function Add(a: Int, b: Int): Int {
  return a + b;
}

export Add;

The callable Add will show up in this project's API as MathStuff.Add(), because export statements export items from the namespace they were exported from. That means that if you export Add() from the namespace Foo.Bar, it will show up to consumers of the project as Foo.Bar.Add().

In a similar manner to imports, exports can also be aliased:

function Add(a: Int, b: Int): Int {
  return a + b;
}

export Add as MyAdd;

Export statements export items for external projects. All items are available to other namespaces within the same project by default, without any exporting needed.

The Main.qs convention

In a project, if there's a namespace called Main, it is treated as the root of the project. So, if you have the below structure:

src/
   Foo.qs
   Main.qs
   Bar.qs

and a consumer of the project with the manifest:

{
  "author": "Microsoft",
  "license": "MIT",
  "dependencies": {
    "MyLibrary": {
      "path": "/path/to/other/project/on/disk"
    }
  }
}

Anything exported from Main.qs, say a callable X, will show up in the consumer of the project as MyLibrary.X(). The behavior of items exported from Foo.qs and Bar.qs is unchanged; an item X exported from these namespaces would show up as MyLibrary.Foo.X() and MyLibrary.Bar.X().