Repository: microsoft/qsharp
Pull request #660 (2023-09-07 08:00:32)

Publish artifacts via ADO pipeline
This is a variation on Ian's #641 that deals with naming and versioning a little differently.

Still some minor follow up TODOs, but want to get this in now.


Patch:
diff --git a/.ado/publish.yml b/.ado/publish.yml
index a640aaa9..4d4e435d 100644
--- a/.ado/publish.yml
+++ b/.ado/publish.yml
@@ -1,11 +1,8 @@
-# Publishing VSCode Extensions https://code.visualstudio.com/api/working-with-extensions/publishing-extension
+# Publishing VSCode Extensions: https://code.visualstudio.com/api/working-with-extensions/publishing-extension
 #   * $(PAT): https://stackoverflow.com/questions/58192624/publishing-vs-code-extension-via-azure-devops/58195815#58195815
 #   * Extension Manifest (package.json): https://code.visualstudio.com/api/references/extension-manifest
-
-variables:
-  Ver.Major: 0
-  Ver.Minor: 0
-  Ver.Patch: 0
+# Building Py .whl for multiple Linux distros - manylinux: https://github.com/pypa/manylinux
+# aarch64 (ARM64) support for manylinux builds: https://codepyre.com/2019/12/arming-yourself/
 
 name: $(BuildId)
 
@@ -13,33 +10,203 @@ trigger: none
 pr: none
 
 jobs:
-- job: "Publish"
-  pool: 
-    vmImage: 'ubuntu-latest'
+- job: "Build"
+  strategy:
+    matrix:
+      linux_x64:                        # 2023.06.30 ESRP Publishing of Py packs is not supported for linux_x86_64.
+                                        # The "manylinux" approach is used.
+        imageName: 'ubuntu-latest'      # Manylinux Py (x86_64) + VSCode Ext.
+        arch: x86_64
+      linux_ARM64:
+        imageName: 'ubuntu-latest'      # Manylinux Py (ARM64). Takes 45 - 65 minutes, hence is in a separate job.
+        arch: aarch64
+      mac:
+        imageName: 'macOS-latest'       # MacOS-specific Py (Mac is usually quite limited).
+        arch: x86_64
+      windows:
+        imageName: 'windows-latest'     # Win-specific Py + Platform-independent Py.
+        arch: x86_64
+  pool:
+    vmImage: $(imageName)
+  variables:
+    arch: $(arch)
+  timeoutInMinutes: 90
+
   steps:
   - task: UsePythonVersion@0
     inputs:
       versionSpec: '3.11'
 
   - script: |
-      python ./prereqs.py --install
+      python ./prereqs.py --install && python ./version.py
+    displayName: Install Prereqs and set version
+
+  - script: |
+      rustup target add aarch64-apple-darwin
+    displayName: Add aarch64 Rust target on macOS
+    condition: eq(variables['Agent.OS'], 'Darwin')
+
+  # Below VS Code extension build only needs to run on one platform (Linux x86_64 for now)
+  - script: |
       npm install -g @vscode/vsce
-    displayName: Install VSCE Pub Prereqs
-    
+    displayName: Install Prereqs for VSCode Extension
+    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'x86_64'))
+
   - script: |
       python build.py --wasm --npm --vscode
     displayName: Build VSCode Extension
-      
+    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'x86_64'))
+
+  # TODO: When the VSCode Extension is ready for publishing, remove the `--pre-release` flag for 'stable' BUILD_TYPE
   - script: |
-      cp ../LICENSE.txt .
-      vsce package $(Ver.Major).$(Ver.Minor).$(Ver.Patch)
+      vsce package --pre-release
     displayName: Pack VSCode Extension
     workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'
+    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'x86_64'))
+
+  - publish: $(System.DefaultWorkingDirectory)/vscode
+    artifact: VSIX
+    displayName: Upload VSCode Extension Artifact
+    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'x86_64'))
+
+  - script: |
+      python build.py --pip --no-check --no-test --no-check-prereqs
+    displayName: Build Platform-Dependent Py Packages, non-Linux
+    condition: ne(variables['Agent.OS'], 'Linux')
+
+  - script: |
+      set -x -e
+
+      export ARCH=${{ variables['arch'] }}
+
+      if [ "$ARCH" == "aarch64" ]; then
+        # The aarch64 (ARM64) emulation support:
+        sudo apt-get update
+        sudo apt-get install -y --no-install-recommends \
+          qemu qemu-system-misc qemu-user-static qemu-user
+      fi
+
+      chmod +x pip/build_manylinux.sh
+
+      # images: https://github.com/pypa/manylinux#docker-images
+      docker run \
+        --env ARCH=$ARCH --rm -i -v `pwd`:/io \
+        quay.io/pypa/manylinux_2_28_$ARCH \
+        /io/pip/build_manylinux.sh
+
+      ls target/wheels
+    displayName: Build Platform-Dependent Py Packages, Linux
+    condition: eq(variables['Agent.OS'], 'Linux')
+
+  # Build JupyterLab on Windows (was seeing some Access Denied errors on Linux)
+  - script: |
+      python build.py --jupyterlab --no-check
+    displayName: Build Platform-Independent Py Packages
+    condition: eq(variables['Agent.OS'], 'Windows_NT')
+
+  - script: |
+      dir target\wheels\*
+    displayName: List Py Packages on Win
+    condition: eq(variables['Agent.OS'], 'Windows_NT')
+
+  - script: |
+      ls target/wheels/*
+    displayName: List Py Packages on non-Win
+    condition: ne(variables['Agent.OS'], 'Windows_NT')
+
+  - publish: $(System.DefaultWorkingDirectory)/target/wheels
+    artifact: Wheels.Mac
+    displayName: Upload Python Artifacts Mac
+    condition: eq(variables['Agent.OS'], 'Darwin')
+
+  - publish: $(System.DefaultWorkingDirectory)/target/wheels
+    artifact: Wheels.Win
+    displayName: Upload Python Artifacts Win
+    condition: eq(variables['Agent.OS'], 'Windows_NT')
+
+  - publish: $(System.DefaultWorkingDirectory)/target/wheels
+    artifact: Wheels.Linux.${{ variables['arch'] }}
+    displayName: Upload Python Artifacts Linux
+    condition: eq(variables['Agent.OS'], 'Linux')
+
+# TODO: For an automated nightly release, the approval requirement should be skipped
+- job: "Approval"
+  dependsOn: Build
+  pool: server
+  timeoutInMinutes: 1440 # job times out in 1 day
+  steps:
+  - task: ManualValidation@0
+    timeoutInMinutes: 1440 # task times out in 1 day
+    inputs:
+      notifyUsers: ''
+      instructions: 'Please verify artifacts and approve the release'
+      onTimeout: 'reject'
+
+- job: "Publish"
+  dependsOn: Approval
+  pool:
+    vmImage: 'ubuntu-latest'
+
+  steps:
+  - download: current
+    artifact: Wheels.Win
+    displayName: Download Python Artifacts Win
+
+  - download: current
+    artifact: Wheels.Mac
+    displayName: Download Python Artifacts Mac
+
+  - download: current
+    artifact: Wheels.Linux.x86_64
+    displayName: Download Python Artifacts Linux
+
+  - download: current
+    artifact: Wheels.Linux.aarch64
+    displayName: Download Python Artifacts Linux
+
+  - script: |
+      mkdir -p                            target/wheels
+      mv ../Wheels.Linux.x86_64/*.whl     target/wheels
+      mv ../Wheels.Linux.aarch64/*.whl    target/wheels
+      mv ../Wheels.Win/*.whl              target/wheels
+      mv ../Wheels.Mac/*.whl              target/wheels
+      ls                                  target/wheels/*
+    displayName: Move Py Artifacts to Publishing Dir
+
+  - download: current
+    artifact: VSIX
+    displayName: Download VSCode Extension Artifact
 
   - script: |
-      vsce publish --pre-release --pat $(PAT) 2>&1 > pub.log
+      npm install -g @vscode/vsce
+    displayName: Install Prereqs for VSCode Ext Publishing
+
+
+  # NB: Publishing must be the last thing (done only if all previous steps are successful).
+
+  - task: EsrpRelease@2
+    inputs:
+     ConnectedServiceName: 'ESRP_Release'
+     Intent: 'PackageDistribution'
+     ContentType: 'PyPi'
+     PackageLocation: '$(System.DefaultWorkingDirectory)/target/wheels'
+     Owners: '$(OwnerPersonalAlias)@microsoft.com'  # NB: ESRP corrected from group email `qdevtools` to personal one.
+                                                    #     Group email here fails the task with non-actionable output.
+     Approvers: 'billti@microsoft.com'
+     # Auto-inserted Debugging defaults:
+     ServiceEndpointUrl: 'https://api.esrp.microsoft.com'
+     MainPublisher: 'QuantumDevelpmentKit'          # ESRP Team's Correction (including the critical typo "Develpm").
+     DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47'
+    displayName: Publish Py Packages
+
+  # TODO: When the VSCode Extension is ready for publishing, remove the `--pre-release` flag for 'stable' BUILD_TYPE
+  - script: |
+      VSIX_RPATH=../VSIX
+      VSIX_FNAME=`ls $VSIX_RPATH`
+      vsce publish --pre-release --packagePath $VSIX_RPATH/$VSIX_FNAME 2>&1 > pub.log
     displayName: Publish VSCode Extension
-    workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'
+    env:
+      VSCE_PAT: $(PAT)
 
   - script: |
       dir
@@ -47,3 +214,5 @@ jobs:
     displayName: If failed, display VSCode Publishing Results
     condition: failed()
     workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'
+
+# TODO: npm package publishing, and JupyterLab extension publishing.
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index c49549a9..fdc01533 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -11,7 +11,7 @@ module.exports = {
     "/npm/lib/",
     "/npm/src/*.generated.ts",
     "/jupyterlab/lib",
-    "/jupyterlab/qsharp_jupyterlab/labextension",
+    "/jupyterlab/qsharp-jupyterlab/labextension",
     "/vscode/out/",
   ],
   env: {
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 31578c07..fa16422e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -99,6 +99,10 @@ jobs:
         with:
           toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
           components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
+      - name: Add additional Rust targets
+        run: |
+          rustup target add aarch64-apple-darwin
+        if: matrix.os == 'macos-latest'
       - uses: actions/setup-python@v4
         with:
           python-version: '3.11'
diff --git a/.prettierignore b/.prettierignore
index c5867e05..53c93c42 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -10,7 +10,7 @@ __pycache__/
 .venv/
 /compiler/
 /jupyterlab/lib/
-/jupyterlab/qsharp_jupyterlab/labextension/
+/jupyterlab/qsharp-jupyterlab/labextension/
 /katas/**/*.md
 /library/
 /npm/dist/
diff --git a/Cargo.lock b/Cargo.lock
index b685becf..a044d616 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -891,7 +891,7 @@ dependencies = [
 ]
 
 [[package]]
-name = "qsharp_python"
+name = "qsharp"
 version = "0.0.0"
 dependencies = [
  "miette",
diff --git a/Cargo.toml b/Cargo.toml
index ef861378..cd30dcfb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,7 @@ homepage = "https://github.com/microsoft/qsharp"
 repository = "https://github.com/microsoft/qsharp"
 edition = "2021"
 license = "MIT"
+version = "0.0.0"
 
 [workspace.dependencies]
 clap = "4.1.8"
@@ -53,4 +54,5 @@ pyo3 = { version = "0.19.2", features = ["abi3-py37", "extension-module"] }
 quantum-sparse-sim = { git = "https://github.com/qir-alliance/qir-runner", rev = "e96b9a12a43e98f83f2d4d499f46d651d0c6c341", default-features = false }
 
 [profile.release]
+debug = 1
 strip = true
diff --git a/build.py b/build.py
index 5eb5b738..909ac0ef 100755
--- a/build.py
+++ b/build.py
@@ -53,9 +53,17 @@ parser.add_argument(
     help="Run the linting and formatting checks (default is --check)",
 )
 
+parser.add_argument(
+    "--check-prereqs",
+    action=argparse.BooleanOptionalAction,
+    default=True,
+    help="Run the prerequisites check (default is --check-prereqs)",
+)
+
 args = parser.parse_args()
 
-check_prereqs()
+if args.check_prereqs:
+    check_prereqs()
 
 # If no specific project given then build all
 build_all = (
@@ -79,12 +87,17 @@ build_jupyterlab = build_all or args.jupyterlab
 
 # JavaScript projects and eslint, prettier depend on npm_install
 # However the JupyterLab extension uses yarn in a separate workspace
-npm_install_needed = build_npm or build_play or build_vscode or args.check
+npm_install_needed = (
+    build_npm or build_play or build_vscode or build_jupyterlab or args.check
+)
 npm_cmd = "npm.cmd" if platform.system() == "Windows" else "npm"
 
 build_type = "debug" if args.debug else "release"
 run_tests = args.test
 
+# TODO: This requires that both targets are installed on macOS to build Python packages. Add to prereqs checks.
+pip_archflags = "-arch x86_64 -arch arm64" if platform.system() == "Darwin" else None
+
 root_dir = os.path.dirname(os.path.abspath(__file__))
 wasm_src = os.path.join(root_dir, "wasm")
 wasm_bld = os.path.join(root_dir, "target", "wasm32", build_type)
@@ -166,6 +179,12 @@ if build_pip:
         # Already in a virtual environment, use current Python
         python_bin = sys.executable
 
+    # copy the process env vars
+    pip_env: dict[str, str] = os.environ.copy()
+    if pip_archflags is not None:
+        # if on mac, add the arch flags for universal binary
+        pip_env["ARCHFLAGS"] = pip_archflags
+
     pip_build_args = [
         python_bin,
         "-m",
@@ -175,7 +194,7 @@ if build_pip:
         wheels_dir,
         pip_src,
     ]
-    subprocess.run(pip_build_args, check=True, text=True, cwd=pip_src)
+    subprocess.run(pip_build_args, check=True, text=True, cwd=pip_src, env=pip_env)
 
     if run_tests:
         print("Running tests for the pip package")
@@ -197,7 +216,7 @@ if build_pip:
             "--force-reinstall",
             "--no-index",
             "--find-links=" + wheels_dir,
-            "qsharp",
+            f"qsharp-lang",
         ]
         subprocess.run(pip_install_args, check=True, text=True, cwd=pip_src)
         pytest_args = [python_bin, "-m", "pytest"]
diff --git a/compiler/qsc/Cargo.toml b/compiler/qsc/Cargo.toml
index 43919c91..04308be0 100644
--- a/compiler/qsc/Cargo.toml
+++ b/compiler/qsc/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "qsc"
-version = "0.0.0"
 description = "Q# compiler"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_ast/Cargo.toml b/compiler/qsc_ast/Cargo.toml
index 1cd14147..af284a72 100644
--- a/compiler/qsc_ast/Cargo.toml
+++ b/compiler/qsc_ast/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_ast"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_codegen/Cargo.toml b/compiler/qsc_codegen/Cargo.toml
index 366ca666..1b16c1ad 100644
--- a/compiler/qsc_codegen/Cargo.toml
+++ b/compiler/qsc_codegen/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_codegen"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_data_structures/Cargo.toml b/compiler/qsc_data_structures/Cargo.toml
index e894e95a..da27de37 100644
--- a/compiler/qsc_data_structures/Cargo.toml
+++ b/compiler/qsc_data_structures/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_data_structures"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 edition.workspace = true
 homepage.workspace = true
diff --git a/compiler/qsc_eval/Cargo.toml b/compiler/qsc_eval/Cargo.toml
index 59d3638b..af8fbe16 100644
--- a/compiler/qsc_eval/Cargo.toml
+++ b/compiler/qsc_eval/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_eval"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_fir/Cargo.toml b/compiler/qsc_fir/Cargo.toml
index c2bc301d..cf6e3ec3 100644
--- a/compiler/qsc_fir/Cargo.toml
+++ b/compiler/qsc_fir/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_fir"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_frontend/Cargo.toml b/compiler/qsc_frontend/Cargo.toml
index 28985e6b..b2bf5d92 100644
--- a/compiler/qsc_frontend/Cargo.toml
+++ b/compiler/qsc_frontend/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_frontend"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_hir/Cargo.toml b/compiler/qsc_hir/Cargo.toml
index ca0e8ed5..18abd528 100644
--- a/compiler/qsc_hir/Cargo.toml
+++ b/compiler/qsc_hir/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_hir"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/compiler/qsc_parse/Cargo.toml b/compiler/qsc_parse/Cargo.toml
index 9a02ee65..c51fb386 100644
--- a/compiler/qsc_parse/Cargo.toml
+++ b/compiler/qsc_parse/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_parse"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 edition.workspace = true
 homepage.workspace = true
diff --git a/compiler/qsc_passes/Cargo.toml b/compiler/qsc_passes/Cargo.toml
index 48a32b2d..8bd6efac 100644
--- a/compiler/qsc_passes/Cargo.toml
+++ b/compiler/qsc_passes/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_passes"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 22f24355..e4d53b62 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "fuzz"
-version = "0.0.0"
 publish = false
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/jupyterlab/.gitignore b/jupyterlab/.gitignore
index 726525d8..27f11957 100644
--- a/jupyterlab/.gitignore
+++ b/jupyterlab/.gitignore
@@ -39,6 +39,6 @@ pip-log.txt
 pip-delete-this-directory.txt
 
 tsconfig.tsbuildinfo
-qsharp_jupyterlab/labextension
-qsharp_jupyterlab/_version.py
+qsharp-jupyterlab/labextension
+qsharp-jupyterlab/_version.py
 .yarn
diff --git a/jupyterlab/README.md b/jupyterlab/README.md
index d335a231..f2674979 100644
--- a/jupyterlab/README.md
+++ b/jupyterlab/README.md
@@ -46,11 +46,11 @@ Then refresh the browser.
 Remove the `pip` package by running:
 
 ```bash
-pip uninstall qsharp_jupyterlab
+pip uninstall qsharp-lang-jupyterlab
 ```
 
 You will also need to remove the symlink created by `jupyter labextension develop`
-command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions` folder is located. Then you can remove the symlink named `qsharp_jupyterlab` within that folder.
+command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions` folder is located. Then you can remove the symlink named `qsharp-lang-jupyterlab` within that folder.
 
 ## Releasing
 
diff --git a/jupyterlab/install.json b/jupyterlab/install.json
index f1fc4723..0acd82a6 100644
--- a/jupyterlab/install.json
+++ b/jupyterlab/install.json
@@ -1,5 +1,5 @@
 {
   "packageManager": "python",
-  "packageName": "qsharp_jupyterlab",
-  "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package qsharp_jupyterlab"
+  "packageName": "qsharp-lang-jupyterlab",
+  "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package qsharp-lang-jupyterlab"
 }
diff --git a/jupyterlab/package.json b/jupyterlab/package.json
index 5cdd9526..73912d83 100644
--- a/jupyterlab/package.json
+++ b/jupyterlab/package.json
@@ -1,5 +1,5 @@
 {
-  "name": "qsharp_jupyterlab",
+  "name": "qsharp-lang-jupyterlab",
   "version": "0.0.0",
   "description": "Q# extension for JupyterLab",
   "keywords": [
@@ -44,6 +44,6 @@
   },
   "jupyterlab": {
     "extension": true,
-    "outputDir": "qsharp_jupyterlab/labextension"
+    "outputDir": "qsharp-jupyterlab/labextension"
   }
 }
diff --git a/jupyterlab/pyproject.toml b/jupyterlab/pyproject.toml
index 11988c2d..8f49d55d 100644
--- a/jupyterlab/pyproject.toml
+++ b/jupyterlab/pyproject.toml
@@ -3,7 +3,8 @@ requires = ["hatchling>=1.4.0", "jupyterlab==4.0.0", "hatch-nodejs-version"]
 build-backend = "hatchling.build"
 
 [project]
-name = "qsharp_jupyterlab"
+name = "qsharp-lang-jupyterlab"
+version = "0.0.0"
 readme = "README.md"
 requires-python = ">=3.7"
 classifiers = [
@@ -23,7 +24,7 @@ classifiers = [
 ]
 dependencies = [
 ]
-dynamic = ["version", "description", "authors", "urls", "keywords"]
+dynamic = ["description", "authors", "urls", "keywords"]
 
 [tool.hatch.version]
 source = "nodejs"
@@ -32,21 +33,21 @@ source = "nodejs"
 fields = ["description", "authors", "urls"]
 
 [tool.hatch.build.targets.sdist]
-artifacts = ["qsharp_jupyterlab/labextension"]
+artifacts = ["qsharp-jupyterlab/labextension"]
 exclude = [".github", "binder"]
 
 [tool.hatch.build.targets.wheel.shared-data]
-"qsharp_jupyterlab/labextension" = "share/jupyter/labextensions/qsharp_jupyterlab"
-"install.json" = "share/jupyter/labextensions/qsharp_jupyterlab/install.json"
+"qsharp-jupyterlab/labextension" = "share/jupyter/labextensions/qsharp-jupyterlab"
+"install.json" = "share/jupyter/labextensions/qsharp-jupyterlab/install.json"
 
 [tool.hatch.build.hooks.version]
-path = "qsharp_jupyterlab/_version.py"
+path = "qsharp-jupyterlab/_version.py"
 
 [tool.hatch.build.hooks.jupyter-builder]
 dependencies = ["hatch-jupyter-builder>=0.5"]
 build-function = "hatch_jupyter_builder.npm_builder"
 ensured-targets = [
-    "qsharp_jupyterlab/labextension/package.json",
+    "qsharp-jupyterlab/labextension/package.json",
 ]
 
 [tool.hatch.build.hooks.jupyter-builder.build-kwargs]
@@ -57,7 +58,7 @@ npm = ["jlpm"]
 build_cmd = "build:dev"
 npm = ["jlpm"]
 source_dir = "src"
-build_dir = "qsharp_jupyterlab/labextension"
+build_dir = "qsharp-jupyterlab/labextension"
 
 [tool.check-wheel-contents]
 ignore = ["W002"]
diff --git a/jupyterlab/qsharp_jupyterlab/__init__.py b/jupyterlab/qsharp-jupyterlab/__init__.py
similarity index 77%
rename from jupyterlab/qsharp_jupyterlab/__init__.py
rename to jupyterlab/qsharp-jupyterlab/__init__.py
index f4389a6b..2fb44c70 100644
--- a/jupyterlab/qsharp_jupyterlab/__init__.py
+++ b/jupyterlab/qsharp-jupyterlab/__init__.py
@@ -4,6 +4,6 @@ from ._version import __version__
 def _jupyter_labextension_paths():
     return [{
         "src": "labextension",
-        "dest": "qsharp_jupyterlab"
+        "dest": "qsharp-jupyterlab"
     }]
 
diff --git a/jupyterlab/yarn.lock b/jupyterlab/yarn.lock
index c19c52d7..114e3471 100644
--- a/jupyterlab/yarn.lock
+++ b/jupyterlab/yarn.lock
@@ -2746,9 +2746,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"qsharp_jupyterlab@workspace:.":
+"qsharp-lang-jupyterlab@workspace:.":
   version: 0.0.0-use.local
-  resolution: "qsharp_jupyterlab@workspace:."
+  resolution: "qsharp-lang-jupyterlab@workspace:."
   dependencies:
     "@codemirror/language": 6.6.0
     "@codemirror/legacy-modes": 6.3.2
diff --git a/katas/Cargo.toml b/katas/Cargo.toml
index 347c1ace..e09ca05c 100644
--- a/katas/Cargo.toml
+++ b/katas/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "katas"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/language_service/Cargo.toml b/language_service/Cargo.toml
index a85e8d5a..37e2c5aa 100644
--- a/language_service/Cargo.toml
+++ b/language_service/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsls"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 edition.workspace = true
 homepage.workspace = true
diff --git a/npm/package.json b/npm/package.json
index 26fb19fe..2e962f28 100644
--- a/npm/package.json
+++ b/npm/package.json
@@ -1,7 +1,7 @@
 {
-  "name": "qsharp",
+  "name": "qsharp-lang",
   "description": "qsharp language package for quantum development",
-  "version": "0.1.0",
+  "version": "0.0.0",
   "license": "MIT",
   "engines": {
     "node": ">=16.17.0"
diff --git a/package-lock.json b/package-lock.json
index 1c155f02..a53e6ac8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1907,16 +1907,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/qsharp": {
+    "node_modules/qsharp-lang": {
       "resolved": "npm",
       "link": true
     },
-    "node_modules/qsharp-playground": {
-      "resolved": "playground",
+    "node_modules/qsharp-lang-vscode-dev": {
+      "resolved": "vscode",
       "link": true
     },
-    "node_modules/qsharp-vscode": {
-      "resolved": "vscode",
+    "node_modules/qsharp-playground": {
+      "resolved": "playground",
       "link": true
     },
     "node_modules/queue-microtask": {
@@ -2232,8 +2232,8 @@
       }
     },
     "npm": {
-      "name": "qsharp",
-      "version": "0.1.0",
+      "name": "qsharp-lang",
+      "version": "0.0.0",
       "license": "MIT",
       "engines": {
         "node": ">=16.17.0"
@@ -2245,7 +2245,7 @@
       "license": "MIT"
     },
     "vscode": {
-      "name": "qsharp-vscode",
+      "name": "qsharp-lang-vscode-dev",
       "version": "0.0.0",
       "license": "SEE LICENSE IN LICENSE.txt",
       "engines": {
diff --git a/pip/Cargo.toml b/pip/Cargo.toml
index 13478eb0..21a0f588 100644
--- a/pip/Cargo.toml
+++ b/pip/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
-name = "qsharp_python"
-version = "0.0.0"
+name = "qsharp"
 description = "Q# Python Bindings"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true
diff --git a/pip/build_manylinux.sh b/pip/build_manylinux.sh
new file mode 100644
index 00000000..77c5f87f
--- /dev/null
+++ b/pip/build_manylinux.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Is to be executed in the Manylinux Docker container.
+# https://github.com/pypa/manylinux
+
+# Generates the manylinux .whl file.
+# Input:
+#   "/io" is mapped to this repo dir "qsharp" (from YAML, from repo dir  "docker run -v `pwd`:/io").
+#   Environment (from YAML `docker run --env ARCH=x86_64`):
+#       ARCH: Architecture: x86_64 or aarch64, etc.
+# Output:
+#   "<this repo>/target/wheels/qsharp-lang-*-cp3*-abi3-manylinux*_$ARCH.whl",
+#       e.g., "<this repo>/target/wheels/qsharp-lang-0.0.7-cp37-abi3-manylinux_2_28_x86_64.whl".
+
+set -x -e
+
+# Install Rust:
+curl --proto '=https' --tlsv1.2 -sS https://sh.rustup.rs > rustup-init.sh
+chmod +x rustup-init.sh
+./rustup-init.sh -y
+source "$HOME/.cargo/env"
+
+# Enter this repo dir:
+cd /io
+
+# Build the platform-dependent Linux .whl:
+/opt/python/cp311-cp311/bin/python ./build.py --pip --no-check --no-test --no-check-prereqs
+
+# Make the generated Linux .whl a manylinux .whl:
+export WHEEL_DIR_APATH=/io/target/wheels
+export WHEEL_FILE_APATH=$WHEEL_DIR_APATH/qsharp_lang-*-cp37-abi3-linux_$ARCH.whl
+auditwheel repair --wheel-dir $WHEEL_DIR_APATH $WHEEL_FILE_APATH
+# The result is in, for example, "<this repo>/target/wheels/qsharp-lang-x.y.z-cp37-abi3-manylinux_2_28_x86_64.whl".
+rm -fR $WHEEL_FILE_APATH    # Remove the platform-dependent Linux .whl (manylinux one remains).
+
+exit  # From the Docker container
diff --git a/pip/pyproject.toml b/pip/pyproject.toml
index 74c9ffd0..8c55e90e 100644
--- a/pip/pyproject.toml
+++ b/pip/pyproject.toml
@@ -1,5 +1,5 @@
 [project]
-name = "qsharp"
+name = "qsharp-lang"
 version = "0.0.0"
 requires-python = ">= 3.7"
 classifiers = [
@@ -19,8 +19,11 @@ classifiers = [
 ]
 
 [project.optional-dependencies]
-jupyterlab = ["qsharp_jupyterlab"]
+jupyterlab = ["qsharp-lang-jupyterlab"]
 
 [build-system]
-requires = ["maturin ~= 0.14.16"]
+requires = ["maturin ~= 1.2.0"]
 build-backend = "maturin"
+
+[tool.maturin]
+module-name = "qsharp._native"
diff --git a/playground/src/compiler-worker.ts b/playground/src/compiler-worker.ts
index 55c9ec83..96592202 100644
--- a/playground/src/compiler-worker.ts
+++ b/playground/src/compiler-worker.ts
@@ -1,6 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { messageHandler } from "qsharp/compiler-worker";
+import { messageHandler } from "qsharp-lang/compiler-worker";
 
 self.onmessage = messageHandler;
diff --git a/playground/src/editor.tsx b/playground/src/editor.tsx
index b37dcb6e..c6a1070a 100644
--- a/playground/src/editor.tsx
+++ b/playground/src/editor.tsx
@@ -14,7 +14,7 @@ import {
   QscEventTarget,
   VSDiagnostic,
   log,
-} from "qsharp";
+} from "qsharp-lang";
 import { codeToCompressedBase64 } from "./utils.js";
 import { ActiveTab } from "./main.js";
 
diff --git a/playground/src/kata.tsx b/playground/src/kata.tsx
index c5f73aac..014e8c51 100644
--- a/playground/src/kata.tsx
+++ b/playground/src/kata.tsx
@@ -12,7 +12,7 @@ import {
   QscEventTarget,
   Question,
   VSDiagnostic,
-} from "qsharp";
+} from "qsharp-lang";
 import { Editor } from "./editor.js";
 import { OutputTabs } from "./tabs.js";
 
diff --git a/playground/src/language-service-worker.ts b/playground/src/language-service-worker.ts
index d603dd2e..2b4e4ca1 100644
--- a/playground/src/language-service-worker.ts
+++ b/playground/src/language-service-worker.ts
@@ -1,6 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { messageHandler } from "qsharp/language-service-worker";
+import { messageHandler } from "qsharp-lang/language-service-worker";
 
 self.onmessage = messageHandler;
diff --git a/playground/src/main.tsx b/playground/src/main.tsx
index e6d182f8..10ef5301 100644
--- a/playground/src/main.tsx
+++ b/playground/src/main.tsx
@@ -15,7 +15,7 @@ import {
   samples,
   getLanguageServiceWorker,
   ILanguageService,
-} from "qsharp";
+} from "qsharp-lang";
 
 import { Nav } from "./nav.js";
 import { Editor } from "./editor.js";
diff --git a/playground/src/results.tsx b/playground/src/results.tsx
index 2ea26489..8a050fd1 100644
--- a/playground/src/results.tsx
+++ b/playground/src/results.tsx
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { QscEventTarget, ShotResult, VSDiagnostic } from "qsharp";
+import { QscEventTarget, ShotResult, VSDiagnostic } from "qsharp-lang";
 import { useEffect, useState } from "preact/hooks";
 
 import { Histogram } from "./histo.js";
diff --git a/playground/src/state.tsx b/playground/src/state.tsx
index a0d239ff..5d613944 100644
--- a/playground/src/state.tsx
+++ b/playground/src/state.tsx
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { Dump } from "qsharp";
+import { Dump } from "qsharp-lang";
 
 function probability(real: number, imag: number) {
   return real * real + imag * imag;
diff --git a/playground/src/tabs.tsx b/playground/src/tabs.tsx
index 6c96f2d5..55eb9fc7 100644
--- a/playground/src/tabs.tsx
+++ b/playground/src/tabs.tsx
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { QscEventTarget, VSDiagnostic } from "qsharp";
+import { QscEventTarget, VSDiagnostic } from "qsharp-lang";
 import { ResultsTab } from "./results.js";
 import { ActiveTab } from "./main.js";
 
diff --git a/version.py b/version.py
new file mode 100755
index 00000000..64947aab
--- /dev/null
+++ b/version.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+import os
+from datetime import datetime, timezone
+
+# To be updated every time we start a new major.minor version.
+major_minor = "1.0"
+
+# Default to 'dev' builds with a YYMMDD build number
+BUILD_TYPE = os.environ.get("BUILD_TYPE") or "dev"
+BUILD_NUMBER = os.environ.get("BUILD_NUMBER") or "YYMMDD"
+
+build_ver = datetime.now(timezone.utc).strftime("%y%m%d")
+
+if BUILD_TYPE not in ["dev", "rc", "stable"]:
+    print("BUILD_TYPE environment variable must be 'dev', 'rc', or 'stable'")
+    exit(1)
+
+print("Build type: {}".format(BUILD_TYPE))
+
+# Override the dev build number if provided as an environment variable.
+if BUILD_TYPE == "dev" and BUILD_NUMBER != "YYMMDD":
+    try:
+        build_ver = int(BUILD_NUMBER)
+    except:
+        print("BUILD_NUMBER environment variable is not valid")
+        exit(1)
+
+# Default to the dev build formats
+
+# Python dev version of the format "2.3.0.dev1440"
+pip_version = "{}.0.dev{}".format(major_minor, build_ver)
+
+# Npm dev version of the format "2.3.0-dev.1440"
+npm_version = "{}.0-dev.{}".format(major_minor, build_ver)
+
+# VS Code dev version of the format "2.3.1440" (they don't support pre-release versions)
+vscode_version = "{}.{}".format(major_minor, build_ver)
+
+# Check if the environment variable BUILD_TYPE is set to 'rc' or 'stable'.
+# If it is, we should only use a provided build number, not a default build number.
+if BUILD_TYPE in ["rc", "stable"]:
+    try:
+        # Ensure build number is an integer.
+        build_ver = int(BUILD_NUMBER)
+    except:
+        print("BUILD_NUMBER environment variable is not set to an integer")
+        exit(1)
+
+    # Python rc/stable version of the format "2.3.1rc0" or "2.3.1"
+    pip_version = "{}.{}{}".format(
+        major_minor, build_ver, "" if BUILD_TYPE == "stable" else "rc0"
+    )
+
+    # Npm rc/stable version of the format "2.3.1-rc" or "2.3.1"
+    npm_version = "{}.{}{}".format(
+        major_minor, build_ver, "" if BUILD_TYPE == "stable" else "-rc"
+    )
+
+    # VS Code rc/stable version of the format "2.3.1" (same for rc or stable)
+    vscode_version = "{}.{}".format(major_minor, build_ver)
+
+print("Pip version: {}".format(pip_version))
+print("Npm version: {}".format(npm_version))
+print("VS Code version: {}".format(vscode_version))
+
+
+def update_file(file, old_text, new_text):
+    # Open the file and replace the first string matching the old text with the new text
+    with open(file, "r+", newline="") as f:
+        contents = f.read()
+        new_contents = contents.replace(old_text, new_text, 1)
+        f.seek(0)
+        f.write(new_contents)
+        f.truncate()
+
+
+root_dir = os.path.dirname(os.path.abspath(__file__))
+update_file(
+    os.path.join(root_dir, "pip/pyproject.toml"),
+    r'version = "0.0.0"',
+    r'version = "{}"'.format(pip_version),
+)
+
+update_file(
+    os.path.join(root_dir, "jupyterlab/pyproject.toml"),
+    r'version = "0.0.0"',
+    r'version = "{}"'.format(pip_version),
+)
+
+update_file(
+    os.path.join(root_dir, "npm/package.json"),
+    r'"version": "0.0.0",',
+    r'"version": "{}",'.format(npm_version),
+)
+
+update_file(
+    os.path.join(root_dir, "vscode/package.json"),
+    r'"version": "0.0.0",',
+    r'"version": "{}",'.format(vscode_version),
+)
+
+# If not a 'dev' build, update the VS Code extension identifier to be the non-dev version
+if BUILD_TYPE != "dev":
+    update_file(
+        os.path.join(root_dir, "vscode/package.json"),
+        r'"name": "qsharp-lang-vscode-dev",',
+        r'"name": "qsharp-lang-vscode",',
+    )
+    # TODO: Update the description and/or readme also for the different extension channels
diff --git a/vscode/.artifactignore b/vscode/.artifactignore
new file mode 100644
index 00000000..eea48d15
--- /dev/null
+++ b/vscode/.artifactignore
@@ -0,0 +1,2 @@
+**/*
+!qsharp-lang-vscode*.vsix
diff --git a/vscode/LICENSE.txt b/vscode/LICENSE.txt
new file mode 100644
index 00000000..9e841e7a
--- /dev/null
+++ b/vscode/LICENSE.txt
@@ -0,0 +1,21 @@
+    MIT License
+
+    Copyright (c) Microsoft Corporation.
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all
+    copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE
diff --git a/vscode/package.json b/vscode/package.json
index 3f37ae9a..daaf777c 100644
--- a/vscode/package.json
+++ b/vscode/package.json
@@ -1,6 +1,6 @@
 {
-  "name": "qsharp-vscode",
-  "displayName": "Q# (preview)",
+  "name": "qsharp-lang-vscode-dev",
+  "displayName": "Azure Quantum Developer Kit (QDK) Preview",
   "description": "Q# Language Support",
   "version": "0.0.0",
   "publisher": "quantum",
diff --git a/vscode/src/compilerWorker.ts b/vscode/src/compilerWorker.ts
index 55c9ec83..96592202 100644
--- a/vscode/src/compilerWorker.ts
+++ b/vscode/src/compilerWorker.ts
@@ -1,6 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { messageHandler } from "qsharp/compiler-worker";
+import { messageHandler } from "qsharp-lang/compiler-worker";
 
 self.onmessage = messageHandler;
diff --git a/vscode/src/completion.ts b/vscode/src/completion.ts
index 7819d3cb..6b8083b0 100644
--- a/vscode/src/completion.ts
+++ b/vscode/src/completion.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { ILanguageService } from "qsharp";
+import { ILanguageService } from "qsharp-lang";
 import * as vscode from "vscode";
 import { CompletionItem } from "vscode";
 
diff --git a/vscode/src/debugger/activate.ts b/vscode/src/debugger/activate.ts
index cc03d4dc..c2dce52e 100644
--- a/vscode/src/debugger/activate.ts
+++ b/vscode/src/debugger/activate.ts
@@ -4,7 +4,7 @@
 /* eslint-disable @typescript-eslint/no-unused-vars */
 
 import * as vscode from "vscode";
-import { IDebugServiceWorker, getDebugServiceWorker } from "qsharp";
+import { IDebugServiceWorker, getDebugServiceWorker } from "qsharp-lang";
 import {
   FileAccessor,
   qsharpExtensionId,
diff --git a/vscode/src/debugger/debug-service-worker.ts b/vscode/src/debugger/debug-service-worker.ts
index f97a4144..80fd66c4 100644
--- a/vscode/src/debugger/debug-service-worker.ts
+++ b/vscode/src/debugger/debug-service-worker.ts
@@ -1,6 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { messageHandler } from "qsharp/debug-service-worker";
+import { messageHandler } from "qsharp-lang/debug-service-worker";
 
 self.onmessage = messageHandler;
diff --git a/vscode/src/debugger/output.ts b/vscode/src/debugger/output.ts
index 4d356e5b..5288b617 100644
--- a/vscode/src/debugger/output.ts
+++ b/vscode/src/debugger/output.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { QscEventTarget } from "qsharp";
+import { QscEventTarget } from "qsharp-lang";
 
 export function createDebugConsoleEventTarget(out: (message: string) => void) {
   const eventTarget = new QscEventTarget(false);
diff --git a/vscode/src/debugger/session.ts b/vscode/src/debugger/session.ts
index 6103fa6a..4e9cfc10 100644
--- a/vscode/src/debugger/session.ts
+++ b/vscode/src/debugger/session.ts
@@ -32,7 +32,7 @@ import {
   IStructStepResult,
   QscEventTarget,
   qsharpLibraryUriScheme,
-} from "qsharp";
+} from "qsharp-lang";
 import { createDebugConsoleEventTarget } from "./output";
 import { ILaunchRequestArguments } from "./types";
 const ErrorProgramHasErrors =
diff --git a/vscode/src/definition.ts b/vscode/src/definition.ts
index 68dadfff..bfee5499 100644
--- a/vscode/src/definition.ts
+++ b/vscode/src/definition.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { ILanguageService } from "qsharp";
+import { ILanguageService } from "qsharp-lang";
 import * as vscode from "vscode";
 
 export function createDefinitionProvider(languageService: ILanguageService) {
diff --git a/vscode/src/diagnostics.ts b/vscode/src/diagnostics.ts
index 5365a709..a2773479 100644
--- a/vscode/src/diagnostics.ts
+++ b/vscode/src/diagnostics.ts
@@ -1,7 +1,11 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { ILanguageService, VSDiagnostic, qsharpLibraryUriScheme } from "qsharp";
+import {
+  ILanguageService,
+  VSDiagnostic,
+  qsharpLibraryUriScheme,
+} from "qsharp-lang";
 import * as vscode from "vscode";
 import { qsharpLanguageId } from "./common.js";
 
diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts
index 85036236..e15831dc 100644
--- a/vscode/src/extension.ts
+++ b/vscode/src/extension.ts
@@ -8,7 +8,7 @@ import {
   log,
   getLibrarySourceContent,
   qsharpLibraryUriScheme,
-} from "qsharp";
+} from "qsharp-lang";
 import * as vscode from "vscode";
 import { createCompletionItemProvider } from "./completion.js";
 import { createDefinitionProvider } from "./definition.js";
diff --git a/vscode/src/hover.ts b/vscode/src/hover.ts
index da0f80ab..5542ad67 100644
--- a/vscode/src/hover.ts
+++ b/vscode/src/hover.ts
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { ILanguageService } from "qsharp";
+import { ILanguageService } from "qsharp-lang";
 import * as vscode from "vscode";
 
 export function createHoverProvider(languageService: ILanguageService) {
diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml
index 4383fda8..475fd36a 100644
--- a/wasm/Cargo.toml
+++ b/wasm/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "qsc_wasm"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 edition.workspace = true
 # wasm-pack doesn't like the workspace format for the below, so copied in for now.


Test patch:
diff --git a/library/tests/Cargo.toml b/library/tests/Cargo.toml
index 365c4a5c..a254e082 100644
--- a/library/tests/Cargo.toml
+++ b/library/tests/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "stdlib_tests"
-version = "0.0.0"
 
+version.workspace = true
 authors.workspace = true
 homepage.workspace = true
 repository.workspace = true