├── .gitignore ├── functions ├── addone.wl └── range.wl ├── .github ├── images │ ├── 4-Add-secret.png │ ├── 5-Create-new-file.png │ ├── 6-Commit-new-file.png │ ├── 1-Use-this-template.png │ ├── 7-Workflow-run-list.png │ ├── 3-New-repository-secret.png │ ├── 8-Workflow-run-detail.png │ ├── 2-Create-repository-from-template.png │ └── 9-Workflow-run-detail-artifacts.png └── workflows │ └── compile-wl-functions.yml ├── LICENSE ├── CONTRIBUTING.md ├── compile.wls └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | compiled/ -------------------------------------------------------------------------------- /functions/addone.wl: -------------------------------------------------------------------------------- 1 | (* 2 | In[1]:= func[42] 3 | Out[1]= 43 4 | *) 5 | 6 | Function[Typed[arg, "MachineInteger"], arg + 1] -------------------------------------------------------------------------------- /.github/images/4-Add-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/4-Add-secret.png -------------------------------------------------------------------------------- /.github/images/5-Create-new-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/5-Create-new-file.png -------------------------------------------------------------------------------- /.github/images/6-Commit-new-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/6-Commit-new-file.png -------------------------------------------------------------------------------- /.github/images/1-Use-this-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/1-Use-this-template.png -------------------------------------------------------------------------------- /.github/images/7-Workflow-run-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/7-Workflow-run-list.png -------------------------------------------------------------------------------- /.github/images/3-New-repository-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/3-New-repository-secret.png -------------------------------------------------------------------------------- /.github/images/8-Workflow-run-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/8-Workflow-run-detail.png -------------------------------------------------------------------------------- /.github/images/2-Create-repository-from-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/2-Create-repository-from-template.png -------------------------------------------------------------------------------- /.github/images/9-Workflow-run-detail-artifacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/WL-FunctionCompile-CI-Template/master/.github/images/9-Workflow-run-detail-artifacts.png -------------------------------------------------------------------------------- /functions/range.wl: -------------------------------------------------------------------------------- 1 | (* 2 | In[1]:= func[20] 3 | Out[1]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} 4 | *) 5 | 6 | Function[Typed[len, "MachineInteger"], Table[i, {i, len}]] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Wolfram Research Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Wolfram® 2 | 3 | Thank you for taking the time to contribute to the [Wolfram Research](https://github.com/wolframresearch) repos on GitHub. 4 | 5 | ## Licensing of Contributions 6 | 7 | By contributing to Wolfram, you agree and affirm that: 8 | 9 | > Wolfram may release your contribution under the terms of the [MIT license](https://opensource.org/licenses/MIT); and 10 | 11 | > You have read and agreed to the [Developer Certificate of Origin](http://developercertificate.org/), version 1.1 or later. 12 | 13 | Please see [LICENSE](LICENSE) for licensing conditions pertaining 14 | to individual repositories. 15 | 16 | 17 | ## Bug reports 18 | 19 | ### Security Bugs 20 | 21 | Please **DO NOT** file a public issue regarding a security issue. 22 | Rather, send your report privately to security@wolfram.com. Security 23 | reports are appreciated and we will credit you for it. We do not offer 24 | a security bounty, but the forecast in your neighborhood will be cloudy 25 | with a chance of Wolfram schwag! 26 | 27 | ### General Bugs 28 | 29 | Please use the repository issues page to submit general bug issues. 30 | 31 | Please do not duplicate issues. 32 | 33 | Please do send a complete and well-written report to us. Note: **the 34 | thoroughness of your report will positively correlate to our willingness 35 | and ability to address it**. 36 | 37 | When reporting issues, always include: 38 | 39 | * Console logs of failed workflow/job runs. -------------------------------------------------------------------------------- /compile.wls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env wolframscript 2 | 3 | $sourceDirectory = "functions" 4 | $sourceFileExtensionPattern = "wl" | "m" | "wxf" | "mx" 5 | 6 | $buildDirectory = "compiled" 7 | Quiet@CreateDirectory[$buildDirectory] 8 | 9 | $platformLibraryExtension = $OperatingSystem // Replace[{ 10 | "Windows" -> "dll", 11 | "MacOSX" -> "dylib", 12 | "Unix" -> "so", 13 | _ -> None 14 | }] 15 | If[ 16 | (* if the $OperatingSystem is not a known value *) 17 | !StringQ[$platformLibraryExtension], 18 | (* then print a failure message and exit *) 19 | Print@TemplateApply[ 20 | "ERROR: Unsupported $OperatingSystem \"`1`\"", 21 | $OperatingSystem 22 | ]; 23 | Exit[1] 24 | ] 25 | 26 | functionPathsToCompile = FileNames[ 27 | __ ~~ "." ~~ $sourceFileExtensionPattern, 28 | $sourceDirectory 29 | ] 30 | 31 | If[ 32 | (* if no function files were found *) 33 | Length[functionPathsToCompile] === 0, 34 | (* then print a failure message and exit *) 35 | Print@TemplateApply[ 36 | "ERROR: No function source files found in directory \"`1`\"", 37 | $sourceDirectory 38 | ]; 39 | Exit[1] 40 | ] 41 | 42 | Print["Function(s) to compile: ", functionPathsToCompile] 43 | 44 | compilationResults = functionPathsToCompile // Map[ 45 | Function[functionPath, Module[{ 46 | compiledFunctionPath = FileNameJoin[{ 47 | $buildDirectory, 48 | FileBaseName[functionPath] <> "." <> $platformLibraryExtension 49 | }], 50 | functionExpression, 51 | compilationResult 52 | }, 53 | 54 | (* import function *) 55 | Print@TemplateApply["Importing function from '`1`'...", {functionPath}]; 56 | 57 | functionExpression = Import[functionPath]; 58 | If[ 59 | (* if the import failed *) 60 | FailureQ[functionExpression], 61 | (* then print a failure message and exit *) 62 | Print@TemplateApply["ERROR: failed to import function from '`1`'.", {functionPath}]; 63 | Exit[1] 64 | ]; 65 | 66 | (* compile function *) 67 | Print@TemplateApply[ 68 | "Compiling function from '`1`' to '`2`'...", 69 | {functionPath, compiledFunctionPath} 70 | ]; 71 | 72 | compilationResult = FunctionCompileExportLibrary[compiledFunctionPath, functionExpression]; 73 | If[ 74 | (* if FunctionCompileExportLibrary didn't return a file path *) 75 | !StringQ[compilationResult], 76 | (* then print a failure message and exit *) 77 | Print@TemplateApply[ 78 | "ERROR: failed to compile function from '`1`' to '`2`'.", 79 | {functionPath, compiledFunctionPath} 80 | ]; 81 | Print["FunctionCompileExportLibrary returned:"]; 82 | Echo[compilationResult]; 83 | Exit[1] 84 | ]; 85 | 86 | Print@TemplateApply[ 87 | "Successfully compiled function from '`1`' to '`2`'.", 88 | {functionPath, compiledFunctionPath} 89 | ]; 90 | 91 | compilationResult 92 | ]] 93 | ] 94 | 95 | Print@TemplateApply["Successfully compiled `1` function(s)!", Length[compilationResults]] 96 | 97 | Exit[0] 98 | -------------------------------------------------------------------------------- /.github/workflows/compile-wl-functions.yml: -------------------------------------------------------------------------------- 1 | name: Compile WL function(s) 2 | on: [push] 3 | jobs: 4 | FunctionCompile-Windows-x86-64: 5 | runs-on: windows-latest 6 | env: 7 | WOLFRAM_SYSTEM_ID: Windows-x86-64 8 | WOLFRAMENGINE_INSTALL_MSI_DOWNLOAD_URL: https://files.wolframcdn.com/packages/winget/13.0.0.0/WolframEngine_13.0.0_WIN.msi 9 | WOLFRAMENGINE_CACHE_KEY: WolframEngine-A 10 | WOLFRAMENGINE_INSTALLATION_SUBDIRECTORY: WolframEngine 11 | steps: 12 | - name: Check out repository 13 | uses: actions/checkout@v2 14 | 15 | - name: Cache/restore Wolfram Engine install 16 | id: cache-restore 17 | uses: actions/cache@v2 18 | env: 19 | WOLFRAMENGINE_INSTALLATION_DIRECTORY: '${{ runner.temp }}\${{ env.WOLFRAMENGINE_INSTALLATION_SUBDIRECTORY }}' 20 | with: 21 | path: ${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }} 22 | key: wolframengine-${{ env.WOLFRAM_SYSTEM_ID }}-${{ env.WOLFRAMENGINE_CACHE_KEY }} 23 | 24 | - name: Download and install Wolfram Engine 25 | if: steps.cache-restore.outputs.cache-hit != 'true' 26 | env: 27 | WOLFRAMENGINE_INSTALLATION_DIRECTORY: '${{ runner.temp }}\${{ env.WOLFRAMENGINE_INSTALLATION_SUBDIRECTORY }}' 28 | WOLFRAMENGINE_INSTALL_MSI_PATH: '${{ runner.temp }}\WolframEngine-Install.msi' 29 | WOLFRAMENGINE_INSTALL_LOG_PATH: '${{ runner.temp }}\WolframEngine-Install.log' 30 | run: | 31 | echo 'Downloading Wolfram Engine installer...' 32 | $msiFile = '${{ env.WOLFRAMENGINE_INSTALL_MSI_PATH }}' 33 | $logFile = '${{ env.WOLFRAMENGINE_INSTALL_LOG_PATH }}' 34 | 35 | Import-Module BitsTransfer 36 | Start-BitsTransfer '${{ env.WOLFRAMENGINE_INSTALL_MSI_DOWNLOAD_URL }}' $msiFile 37 | echo 'Downloaded Wolfram Engine installer.' 38 | 39 | $DataStamp = get-date -Format yyyyMMddTHHmmss 40 | $MSIArguments = @( 41 | "/i" 42 | ('"{0}"' -f $msiFile) 43 | 'INSTALLLOCATION="${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }}"' 44 | "/qn" 45 | "/norestart" 46 | "/L*v" 47 | $logFile 48 | ) 49 | echo 'Installing Wolfram Engine...' 50 | Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow 51 | echo 'Installed Wolfram Engine.' 52 | 53 | - name: Compile function 54 | env: 55 | WOLFRAMENGINE_INSTALLATION_DIRECTORY: '${{ runner.temp }}\${{ env.WOLFRAMENGINE_INSTALLATION_SUBDIRECTORY }}' 56 | WOLFRAMINIT: "-pwfile !cloudlm.wolfram.com -entitlement ${{ secrets.WOLFRAM_LICENSE_ENTITLEMENT_ID }}" 57 | run: | 58 | $env:Path += ';${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }}\' 59 | 60 | wolfram -script ./compile.wls 61 | 62 | - name: Archive compiled libraries 63 | uses: actions/upload-artifact@v2 64 | with: 65 | name: CompiledFunctionLibraries-${{ env.WOLFRAM_SYSTEM_ID }} 66 | path: | 67 | compiled/ 68 | if-no-files-found: error 69 | 70 | FunctionCompile-MacOSX-x86-64: 71 | runs-on: macos-latest 72 | env: 73 | WOLFRAM_SYSTEM_ID: MacOSX-x86-64 74 | WOLFRAMENGINE_CACHE_KEY: WolframEngine-A 75 | WOLFRAMENGINE_INSTALLATION_DIRECTORY: "/Applications/Wolfram Engine.app" 76 | steps: 77 | - name: Check out repository 78 | uses: actions/checkout@v2 79 | 80 | - name: Cache/restore Wolfram Engine install 81 | id: cache-restore 82 | uses: actions/cache@v2 83 | with: 84 | path: ${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }} 85 | key: wolframengine-${{ env.WOLFRAM_SYSTEM_ID }}-${{ env.WOLFRAMENGINE_CACHE_KEY }} 86 | 87 | - name: Install Wolfram Engine 88 | if: steps.cache-restore.outputs.cache-hit != 'true' 89 | run: | 90 | echo 'Installing Wolfram Engine...' 91 | brew install --cask wolfram-engine 92 | echo 'Installed Wolfram Engine.' 93 | 94 | - name: Compile function 95 | env: 96 | WOLFRAMENGINE_EXECUTABLES_DIRECTORY: "${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }}/Contents/Resources/Wolfram Player.app/Contents/MacOS" 97 | WOLFRAMSCRIPT_ENTITLEMENTID: ${{ secrets.WOLFRAM_LICENSE_ENTITLEMENT_ID }} 98 | WOLFRAMSCRIPT_KERNELPATH: "${{ env.WOLFRAMENGINE_INSTALLATION_DIRECTORY }}/Contents/MacOS/WolframKernel" 99 | run: | 100 | export PATH="${{ env.WOLFRAMENGINE_EXECUTABLES_DIRECTORY }}:$PATH" 101 | 102 | wolframscript -debug -verbose -script ./compile.wls 103 | 104 | - name: Archive compiled libraries 105 | uses: actions/upload-artifact@v2 106 | with: 107 | name: CompiledFunctionLibraries-${{ env.WOLFRAM_SYSTEM_ID }} 108 | path: | 109 | compiled/ 110 | if-no-files-found: error 111 | 112 | FunctionCompile-Linux-x86-64: 113 | runs-on: ubuntu-latest 114 | container: 115 | image: wolframresearch/wolframengine:latest 116 | options: --user root 117 | env: 118 | WOLFRAM_SYSTEM_ID: Linux-x86-64 119 | steps: 120 | - name: Check out repository 121 | uses: actions/checkout@v2 122 | 123 | - name: Install build tools 124 | run: | 125 | apt-get -y update 126 | apt-get -y install build-essential 127 | 128 | - name: Compile function 129 | env: 130 | WOLFRAMSCRIPT_ENTITLEMENTID: ${{ secrets.WOLFRAM_LICENSE_ENTITLEMENT_ID }} 131 | run: | 132 | wolframscript -script ./compile.wls 133 | 134 | - name: Archive compiled libraries 135 | uses: actions/upload-artifact@v2 136 | with: 137 | name: CompiledFunctionLibraries-${{ env.WOLFRAM_SYSTEM_ID }} 138 | path: | 139 | compiled/ 140 | if-no-files-found: error 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wolfram Language FunctionCompile CI template 2 | 3 | This repository is a template illustrating [compilation of Wolfram Language functions](https://reference.wolfram.com/language/guide/CodeCompilation.html) as part of a continuous integration (CI) workflow using [GitHub Actions](https://github.com/features/actions). 4 | The [GitHub Actions workflow](.github/workflows/compile-wl-functions.yml) and corresponding [Wolfram Language script](compile.wls) in this repository run automatically on each push, and compile the function source files in the [`/functions`](functions) directory into shared libraries for macOS (Apple Silicon not yet supported), Windows, and Linux. 5 | These shared libraries are suitable for linking into external programs, and can also be loaded into a Wolfram Language kernel at runtime using [`LibraryFunctionLoad`](https://reference.wolfram.com/language/ref/LibraryFunctionLoad.html). 6 | 7 | 8 | ## Using this template 9 | 10 | ### 1. Create a new repository from the template 11 | 12 | Click the **Use this template** button above the file listing view: 13 | 14 | ![Template repository file listing view with "Use this template" button](.github/images/1-Use-this-template.png) 15 | 16 | Enter a name for your new repository and click **Create repository from template**: 17 | 18 | !["Create a new repository from WL-FunctionCompile-CI-Template" screen with "Repository name" field and "Create repository from template" button](.github/images/2-Create-repository-from-template.png) 19 | 20 | This will copy the contents of the template repository, including the GitHub Actions configuration and this README.md file, into a new repository in your account (or the selected organization account). 21 | 22 | You may mark your new repository as either public or private. Bear in mind, however, [GitHub Actions' billing policies](https://docs.github.com/en/github/setting-up-and-managing-billing-and-payments-on-github/about-billing-for-github-actions) regarding repository privacy. 23 | 24 | 25 | ### 2. Create an on-demand license entitlement 26 | 27 | After creating your repository from the template, GitHub Actions will immediately attempt to run the [compilation workflow](.github/workflows/compile-wl-functions.yml) in the repository. 28 | This initial run will fail, as the [Wolfram Engine](https://www.wolfram.com/engine/) kernel used for function compilation will be unable to obtain a license, or ["activate"](https://reference.wolfram.com/language/tutorial/ActivatingMathematica.html). 29 | (You may receive an email notification of this failed workflow run.) 30 | In order to ensure the Wolfram Engine can activate, we will use **on-demand licensing**. 31 | 32 | On-demand licensing is a pay-as-you-go licensing method whereby Wolfram Engine usage is billed against your [Wolfram Service Credits](https://www.wolfram.com/service-credits/) balance at a per-kernel-hour rate. 33 | This method allows you to run arbitrary numbers of concurrent Wolfram Engine kernels for pennies per kernel per hour, and to scale up and down in a cost-effective manner. 34 | You may use the starter Service Credits quota available with a free Wolfram Cloud Basic account for initial experimentation before purchasing more Service Credits. 35 | 36 | An on-demand license entitlement is a reusable license key that can be used to activate one or more Wolfram Engine kernels. 37 | Creating an entitlement requires access to the Wolfram Language. 38 | If you do not have [Wolfram Mathematica](https://www.wolfram.com/mathematica/), a [Wolfram|One](https://www.wolfram.com/wolfram-one/) subscription or another Wolfram Language product, you can sign up for a free [Wolfram Cloud Basic](https://www.wolframcloud.com/) subscription and create an entitlement from within a cloud notebook. 39 | 40 | Use the [`CreateLicenseEntitlement` function](https://reference.wolfram.com/language/ref/CreateLicenseEntitlement.html) to create a new license entitlement linked to your Wolfram Account: 41 | ```wl 42 | In[1]:= entitlement = CreateLicenseEntitlement[<| 43 | "StandardKernelLimit" -> 6, 44 | "LicenseExpiration" -> Quantity[1, "Hours"], 45 | "EntitlementExpiration" -> Quantity[1, "Years"] 46 | |>] 47 | 48 | Out[1]= LicenseEntitlementObject["O-WSTD-DA42-GKX4Z6NR2DSZR", <| 49 | "PolicyID" -> "WSTD", "PolicyName" -> "Standard", "BillingInterval" -> Quantity[900, "Seconds"], 50 | "KernelCosts" -> <| 51 | "Standard" -> Quantity[4., "Credits"/"Hours"], 52 | "Parallel" -> Quantity[4., "Credits"/"Hours"] 53 | |>, 54 | "KernelLimits" -> <|"Standard" -> 6, "Parallel" -> 0|>, 55 | "CreationDate" -> DateObject[{2021, 4, 26, 14, 28, 18.}, "Instant", "Gregorian", -4.], 56 | "ExpirationDate" -> DateObject[{2022, 4, 26, 14, 28, 18.}, "Instant", "Gregorian", -4.], 57 | "LicenseExpirationDuration" -> Quantity[MixedMagnitude[{0, 1.}], MixedUnit[{"Days", "Hours"}]] 58 | |>] 59 | ``` 60 | 61 | Take note of the returned entitlement ID (`O-WSTD-DA42-GKX4Z6NR2DSZR` above); you will need it in the next step. 62 | 63 | The meanings of the specified entitlement settings are: 64 | - `"StandardKernelLimit" -> 6`: Up to six kernels may run concurrently. (This means two copies of the three-OS compilation workflow.) 65 | - `"LicenseExpiration" -> Quantity[1, "Hours"]`: Each kernel may run for up to one hour at a time. 66 | - `"EntitlementExpiration" -> Quantity[1, "Years"]`: The entitlement expires one year after creation. (This means you must create a new entitlement and replace the GitHub secret once a year.) 67 | 68 | You may adjust these settings as needed for your use case. For more information, see the documentation for [`CreateLicenseEntitlement`](https://reference.wolfram.com/language/ref/CreateLicenseEntitlement.html). 69 | 70 | _If you are using GitHub Actions [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners), and you or your organization has a [MathLM](https://reference.wolfram.com/language/tutorial/WhatIsMathLM.html) server, you may able to activate the Wolfram Engine using MathLM instead of on-demand licensing. 71 | This would involve modifying the jobs in the [workflow file](.github/workflows/compile-wl-functions.yml) to each create a [`mathpass` file](https://reference.wolfram.com/language/tutorial/RegistrationAndPasswords.html#46656280) containing the hostname of your MathLM server._ 72 | 73 | 74 | ### 3. Create a repository secret containing your entitlement ID 75 | 76 | A license entitlement ID is a form of license key, and so for reasons of security should not be stored directly in the source tree of a repository, especially if that repository is public. 77 | We will instead store it in an [encrypted repository secret](https://docs.github.com/en/actions/reference/encrypted-secrets) that can be accessed by code running in GitHub Actions jobs. 78 | 79 | Open the **Actions secrets** repository settings page (**Settings > Secrets > Actions**) and click **New repository secret**: 80 | 81 | !["Settings > Secrets > Actions" screen with "New repository secret" button](.github/images/3-New-repository-secret.png) 82 | 83 | Name the new secret `WOLFRAM_LICENSE_ENTITLEMENT_ID` and paste your entitlement ID from step 2 as the value, then click **Add secret**: 84 | 85 | !["Actions secrets / New secret" screen with "Name" and "Value" fields and "Add secret" button](.github/images/4-Add-secret.png) 86 | 87 | Make sure to remove any extraneous whitespace from either side of the entitlement ID. 88 | 89 | 90 | ### 4. Add a new function to the repository 91 | 92 | The [compilation script](compile.wls) compiles function source files in the [`/functions`](functions) directory of the repository. 93 | A function source file must have `.wl`, `.m`, `.wxf`, or `.mx` as its extension. 94 | Files in subdirectories of `/functions` (e.g. `/functions/subdir/file.wl`) are ignored. Resulting compiled libraries are named with the base name of the source function file, so `/functions/addone.wl` is compiled to `addone.dylib` (or `.dll` or `.so`, depending on the target operating system). 95 | 96 | Each function source file (e.g. [`/functions/addone.wl`](functions/addone.wl)) should return a [`Function`](https://reference.wolfram.com/language/ref/Function.html) expression with the appropriate [type annotations](https://reference.wolfram.com/language/ref/Typed.html) for compilation with [`FunctionCompile`](https://reference.wolfram.com/language/ref/FunctionCompile.html)/[`FunctionCompileExportLibrary`](https://reference.wolfram.com/language/ref/FunctionCompileExportLibrary.html). 97 | 98 | You can commit and push a new function source file to your repository using the [Git command-line interface](https://docs.github.com/en/github/managing-files-in-a-repository/adding-a-file-to-a-repository-using-the-command-line) or a graphical Git tool like [GitHub Desktop](https://desktop.github.com/), 99 | or you can use [the GitHub web interface](https://docs.github.com/en/github/managing-files-in-a-repository/creating-new-files). 100 | The web interface is the easiest option for a quick test of your newly configured repository. 101 | 102 | Navigate to the [`/functions`](functions) directory listing and click **Add file > Create new file**: 103 | 104 | !["/functions" directory listing with "Add file > Create new file" button](.github/images/5-Create-new-file.png) 105 | 106 | Name the file `power.wl` and paste the following as its contents: 107 | ```wl 108 | Function[Typed[num, "MachineInteger"], num ^ num] 109 | ``` 110 | 111 | Optionally edit the commit message, and then click **Commit new file**: 112 | 113 | !["Commit new file" screen showing new file named "power.wl" with "Function[...]" as contents](.github/images/6-Commit-new-file.png) 114 | 115 | 116 | ### 5. Download and use a compiled function library 117 | 118 | If you switch to the **Actions** tab, you should see the new workflow run triggered by your commit in step 4: 119 | 120 | !["Actions" tab showing workflow run triggered by a new commit](.github/images/7-Workflow-run-list.png) 121 | 122 | Click on the run to see the status of each job in the run: 123 | 124 | ![Workflow run screen showing details of an in-progress run](.github/images/8-Workflow-run-detail.png) 125 | 126 | This initial run may take 10-15 minutes to finish. 127 | Once all jobs succeed, the produced artifacts will be displayed beneath the list of jobs: 128 | 129 | ![Workflow run screen showing a successful run with artifacts for Linux, MacOSX, and Windows platforms](.github/images/9-Workflow-run-detail-artifacts.png) 130 | 131 | Each artifact is a compressed ZIP file containing the compiled function libraries for the platform indicated in its name. 132 | Download and uncompress the artifact for your platform of choice. 133 | 134 | Load the compiled function library for the new `power` function into a Wolfram Language session using [`LibraryFunctionLoad`](https://reference.wolfram.com/language/ref/LibraryFunctionLoad.html): 135 | ```wl 136 | In[2]:= func = LibraryFunctionLoad["/path/to/CompiledFunctionLibraries-MacOSX-x86-64/power.dylib"] 137 | 138 | Out[2]= CompiledCodeFunction[...] 139 | ``` 140 | 141 | The loaded function can be now used interactively and in code: 142 | ```wl 143 | In[3]:= func[42] 144 | 145 | Out[3]= 150130937545296572356771972164254457814047970568738777235893533016064 146 | ``` --------------------------------------------------------------------------------