Compare commits
15 Commits
feature/te
...
v1.0.10-sf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a60ca28b4 | ||
|
|
2b59b6e974 | ||
|
|
8f594471c0 | ||
|
|
0977e3077f | ||
|
|
f087cd0db9 | ||
|
|
5e615feef5 | ||
|
|
5f1725246f | ||
|
|
829fc90e6f | ||
|
|
cc94674e39 | ||
|
|
f16521adf6 | ||
|
|
fc9d18faff | ||
|
|
ff768a6f68 | ||
|
|
9c0f6f1c72 | ||
|
|
7a7369c9ce | ||
|
|
687593f8d2 |
120
.clang-format
@@ -1,120 +0,0 @@
|
||||
#
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
#
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 140
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- forever
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<Q.*'
|
||||
Priority: 200
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
#KeepLineBreaksForNonEmptyLines: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 150
|
||||
PenaltyBreakBeforeFirstCallParameter: 300
|
||||
PenaltyBreakComment: 500
|
||||
PenaltyBreakFirstLessLess: 400
|
||||
PenaltyBreakString: 600
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 50
|
||||
PenaltyReturnTypeOnItsOwnLine: 300
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
allowed-tools: Bash(git checkout --branch:*), Bash(git add:*), Bash(git status:*), Bash(git push:*), Bash(git commit:*), Bash(gh pr create:*)
|
||||
description: Commit, push, and open a PR
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
- Current git status: !`git status`
|
||||
- Current git diff (staged and unstaged changes): !`git diff HEAD`
|
||||
- Current branch: !`git branch --show-current`
|
||||
|
||||
## Your task
|
||||
|
||||
Based on the above changes:
|
||||
1. Create a new branch if on main
|
||||
2. Create a single commit with an appropriate message
|
||||
3. Push the branch to origin
|
||||
4. Create a pull request using `gh pr create`
|
||||
5. You have the capability to call multiple tools in a single response. You MUST do all of the above in a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls.
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(gh api:*), Bash(gh issue comment:*)
|
||||
description: Find duplicate GitHub issues
|
||||
---
|
||||
|
||||
Find up to 3 likely duplicate issues for a given GitHub issue.
|
||||
|
||||
To do this, follow these steps precisely:
|
||||
|
||||
1. Use an agent to check if the Github issue (a) is closed, (b) does not need to be deduped (eg. because it is broad product feedback without a specific solution, or positive feedback), or (c) already has a duplicates comment that you made earlier. If so, do not proceed.
|
||||
2. Use an agent to view a Github issue, and ask the agent to return a summary of the issue
|
||||
3. Then, launch 5 parallel agents to search Github for duplicates of this issue, using diverse keywords and search approaches, using the summary from #1
|
||||
4. Next, feed the results from #1 and #2 into another agent, so that it can filter out false positives, that are likely not actually duplicates of the original issue. If there are no duplicates remaining, do not proceed.
|
||||
5. Finally, comment back on the issue with a list of up to three duplicate issues (or zero, if there are no likely duplicates)
|
||||
|
||||
Notes (be sure to tell this to your agents, too):
|
||||
|
||||
- Use `gh` to interact with Github, rather than web fetch
|
||||
- Do not use other tools, beyond `gh` (eg. don't use other MCP servers, file edit, etc.)
|
||||
- Make a todo list first
|
||||
- For your comment, follow the following format precisely (assuming for this example that you found 3 suspected duplicates):
|
||||
|
||||
---
|
||||
|
||||
Found 3 possible duplicate issues:
|
||||
|
||||
1. <link to issue>
|
||||
2. <link to issue>
|
||||
3. <link to issue>
|
||||
|
||||
This issue will be automatically closed as a duplicate in 3 days.
|
||||
|
||||
- If your issue is a duplicate, please close it and 👍 the existing issue instead
|
||||
- To prevent auto-closure, add a comment or 👎 this comment
|
||||
|
||||
🤖 OrcaSlicer bot
|
||||
|
||||
---
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
allowed-tools: Bash(gh issue list:*), Bash(gh issue view:*), Bash(gh issue edit:*), TodoWrite
|
||||
description: Triage GitHub issues and label critical ones for oncall
|
||||
---
|
||||
|
||||
You're an oncall triage assistant for GitHub issues. Your task is to identify critical issues that require immediate oncall attention and apply the "oncall" label.
|
||||
|
||||
Repository: OrcaSlicer/OrcaSlicer
|
||||
|
||||
Task overview:
|
||||
|
||||
1. First, get all open bugs updated in the last 3 days with at least 50 engagements:
|
||||
```bash
|
||||
gh issue list --repo OrcaSlicer/OrcaSlicer --state open --label bug --limit 1000 --json number,title,updatedAt,comments,reactions | jq -r '.[] | select((.updatedAt >= (now - 259200 | strftime("%Y-%m-%dT%H:%M:%SZ"))) and ((.comments | length) + ([.reactions[].content] | length) >= 50)) | "\(.number)"'
|
||||
```
|
||||
|
||||
2. Save the list of issue numbers and create a TODO list with ALL of them. This ensures you process every single one.
|
||||
|
||||
3. For each issue in your TODO list:
|
||||
- Use `gh issue view <number> --repo OrcaSlicer/OrcaSlicer --json title,body,labels,comments` to get full details
|
||||
- Read and understand the full issue content and comments to determine actual user impact
|
||||
- Evaluate: Is this truly blocking users from using Claude Code?
|
||||
- Consider: "crash", "stuck", "frozen", "hang", "unresponsive", "cannot use", "blocked", "broken"
|
||||
- Does it prevent core functionality? Can users work around it?
|
||||
- Be conservative - only flag issues that truly prevent users from getting work done
|
||||
|
||||
4. For issues that are truly blocking and don't already have the "oncall" label:
|
||||
- Use `gh issue edit <number> --repo OrcaSlicer/OrcaSlicer --add-label "oncall"`
|
||||
- Mark the issue as complete in your TODO list
|
||||
|
||||
5. After processing all issues, provide a summary:
|
||||
- List each issue number that received the "oncall" label
|
||||
- Include the issue title and brief reason why it qualified
|
||||
- If no issues qualified, state that clearly
|
||||
|
||||
Important:
|
||||
- Process ALL issues in your TODO list systematically
|
||||
- Don't post any comments to issues
|
||||
- Only add the "oncall" label, never remove it
|
||||
- Use individual `gh issue view` commands instead of bash for loops to avoid approval prompts
|
||||
@@ -1,10 +0,0 @@
|
||||
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
||||
deps/
|
||||
build_*/
|
||||
build/
|
||||
localization/
|
||||
sandboxes/
|
||||
resources/*
|
||||
!resources/web/
|
||||
!resources/dailytip
|
||||
!resources/shaders
|
||||
@@ -1,2 +0,0 @@
|
||||
ARG BASE_IMAGE
|
||||
FROM ${BASE_IMAGE}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "OrcaSlicer",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"PLATFORM": "linux/amd64",
|
||||
"BASE_IMAGE": "mcr.microsoft.com/devcontainers/cpp:ubuntu-24.04"
|
||||
},
|
||||
"options": ["--platform=linux/amd64"]
|
||||
},
|
||||
"runArgs": ["--platform=linux/amd64"],
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/desktop-lite:1": {
|
||||
"password": "orca"
|
||||
}
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"forwardPorts": [6080],
|
||||
"portsAttributes": {
|
||||
"6080": {
|
||||
"label": "VNC web client (noVNC)",
|
||||
"onAutoForward": "silent"
|
||||
}
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"onAutoForward": "ignore"
|
||||
},
|
||||
"onCreateCommand": {
|
||||
"Set postCreate executable flag": "chmod +x .devcontainer/postCreate.sh"
|
||||
},
|
||||
"postCreateCommand": "sudo .devcontainer/postCreate.sh"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Update and upgrade all system packages
|
||||
apt update
|
||||
apt upgrade -y
|
||||
|
||||
build_linux="./build_linux.sh -u"
|
||||
echo "-----------------------------------------"
|
||||
echo "Running ${build_linux}..."
|
||||
echo "-----------------------------------------"
|
||||
${build_linux}
|
||||
|
||||
echo "------------------------------"
|
||||
echo "Installing missing packages..."
|
||||
echo "------------------------------"
|
||||
apt install -y libgl1-mesa-dev m4 autoconf libtool
|
||||
@@ -1,30 +0,0 @@
|
||||
Build
|
||||
Build.bat
|
||||
/build/
|
||||
deps/build
|
||||
MYMETA.json
|
||||
MYMETA.yml
|
||||
_build
|
||||
blib
|
||||
xs/buildtmp
|
||||
*.o
|
||||
*.log
|
||||
MANIFEST.bak
|
||||
xs/MANIFEST.bak
|
||||
xs/assertlib*
|
||||
.init_bundle.ini
|
||||
.vs/*
|
||||
local-lib
|
||||
/src/TAGS
|
||||
/.vscode/
|
||||
build-linux/*
|
||||
deps/build-linux/*
|
||||
**/.DS_Store
|
||||
install_*
|
||||
build_*/
|
||||
!build_linux.sh
|
||||
SVG
|
||||
scripts/Dockerfile
|
||||
scripts/DockerBuild.sh
|
||||
scripts/DockerRun.sh
|
||||
scripts/.dockerignore
|
||||
2
.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
||||
github: SoftFever
|
||||
ko_fi: SoftFever
|
||||
custom: https://paypal.me/softfever3d
|
||||
142
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,142 +0,0 @@
|
||||
name: 🐞 Bug Report
|
||||
description: File a bug report
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Thank you for using Orca Slicer and wanting to report a bug.**
|
||||
|
||||
Please note that this is not the place to make feature requests or ask for help.
|
||||
For this, please use the [Feature request](https://github.com/OrcaSlicer/OrcaSlicer/issues/new?assignees=&labels=&projects=&template=feature_request.yml) issue type or you can discuss your idea on our [Discord server](https://discord.gg/P4VE9UY9gJ) with others.
|
||||
|
||||
Before filing, please check if the issue already exists (either open or closed) by using the search bar on the issues page. If it does, comment there. Even if it's closed, we can reopen it based on your comment.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is this issue reproducible in the latest nightly build?
|
||||
description: >
|
||||
Please verify this issue still happens in the latest nightly build first. It may already be fixed there:
|
||||
[Nightly builds](https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds).
|
||||
options:
|
||||
- label: I have checked the latest nightly build and the issue is still reproducible
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this problem?
|
||||
description: Please search to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: OrcaSlicer Version
|
||||
description: Which version of Orca Slicer are you running? You can see the full version in `Help` -> `About Orca Slicer`.
|
||||
placeholder: e.g. 1.9.0
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os_type
|
||||
attributes:
|
||||
label: "Operating System (OS)"
|
||||
description: "What OSes are you are experiencing issues on?"
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- macOS
|
||||
- Windows
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os_version
|
||||
attributes:
|
||||
label: "OS Version"
|
||||
description: "What OS version does this relate to?"
|
||||
placeholder: "i.e. OS: Windows 7/8/10/11 ..., Ubuntu 22.04/Fedora 36 ..., macOS 10.15/11.1/12.3 ..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: system_info
|
||||
attributes:
|
||||
label: Additional system information
|
||||
description: For the performance issue, please also show the CPU, Memory information; For the 3D Rendering issue, please also show the Display Card information.
|
||||
placeholder: |
|
||||
CPU: 11th gen Intel r core tm i7-1185g7/AMD Ryzen 7 6800h/...
|
||||
Memory: 32/16 GB...
|
||||
Display Card: NVIDIA Quadro P400/...
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: printer
|
||||
attributes:
|
||||
label: Printer
|
||||
description: Which printer was selected
|
||||
placeholder: Voron 2.4/VzBot/Prusa MK4/Bambu Lab X1 series/Bambu Lab P1P/...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce_steps
|
||||
attributes:
|
||||
label: How to reproduce
|
||||
description: Please described the detailed steps to reproduce this issue
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual_results
|
||||
attributes:
|
||||
label: Actual results
|
||||
description: What happens after the above steps? Please, enclose a screenshot whenever possible (even when you think the description is clear).
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected_results
|
||||
attributes:
|
||||
label: Expected results
|
||||
description: What should happen after the above steps?
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
id: file_required
|
||||
attributes:
|
||||
value: |
|
||||
Please be sure to add the following files:
|
||||
* Please upload a ZIP archive containing the **project file** used when the problem arise. Please export it just before or after the problem occurs. Even if you did nothing and/or there is no object, export it! (We need the configurations in project file).
|
||||
You can export the project file from the application menu in `File`->`Save project as...`, then zip it
|
||||
* A **log file** for crashes and similar issues.
|
||||
You can find your log file here:
|
||||
Windows: `%APPDATA%\OrcaSlicer\log` or usually `C:\Users\<your username>\AppData\Roaming\OrcaSlicer\log`
|
||||
MacOS: `$HOME/Library/Application Support/OrcaSlicer/log`
|
||||
Linux: `$HOME/.config/OrcaSlicer/log`
|
||||
If Orca Slicer still starts, you can also reach this directory from the application menu in `Help` -> `Show Configuration Folder`
|
||||
You can zip the log directory, or just select the newest logs when this issue happens, and zip them
|
||||
- type: textarea
|
||||
id: file_uploads
|
||||
attributes:
|
||||
label: Project file & Debug log uploads
|
||||
description: Drop the project file and debug log here
|
||||
placeholder: |
|
||||
Project File: `File` -> `Save project as...` then zip it & drop it here
|
||||
Log File: `Help` -> `Show Configuration Folder`, then zip the log directory, or just select the newest logs in `log` when this issue happens and zip them, then drop the zip file here
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: file_checklist
|
||||
attributes:
|
||||
label: Checklist of files to include
|
||||
options:
|
||||
- label: Log file
|
||||
- label: Project file
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Screenshots? References? Anything that will give us more context about the issue you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Support (Discord channel)
|
||||
url: https://discord.gg/P4VE9UY9gJ
|
||||
about: Please ask and answer support "how do I?"questions here.
|
||||
- name: Discussion Forum
|
||||
url: https://github.com/OrcaSlicer/OrcaSlicer/discussions
|
||||
about: Please raise ideas and feature suggestions here.
|
||||
66
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,66 +0,0 @@
|
||||
name: 🚀 Feature Request / Enhancement
|
||||
description: Suggest an improvement to make Orca Slicer even better!
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this feature request!
|
||||
|
||||
If your idea is still at the formulation stage, or you're not sure it would
|
||||
be useful to many users, you can raise it as a discussion topic under [Ideas](https://github.com/OrcaSlicer/OrcaSlicer/discussions/categories/ideas)
|
||||
or you can raise it on the [Discord server](https://discord.gg/P4VE9UY9gJ).
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this feature request?
|
||||
description: |
|
||||
Please search to see if an issue already exists for a feature, or perhaps one similar.
|
||||
You can then comment and react so that we know know much interest there is in the feature request.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: A clear and concise description of what the problem is.
|
||||
placeholder: I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Which printers will be beneficial to this feature?
|
||||
description: Select affected printer firmware type.
|
||||
multiple: true
|
||||
options:
|
||||
- Klipper
|
||||
- Marlin
|
||||
- Others
|
||||
- All
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
placeholder: It should do [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
placeholder: |
|
||||
1. [...]
|
||||
2. [...]
|
||||
3. [...]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: |
|
||||
Add any other context, diagrams, illustations or screenshots about the feature request here.
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
11
.github/actions/apt-install-deps/action.yml
vendored
@@ -1,11 +0,0 @@
|
||||
name: 'Apt Install Deps'
|
||||
description: 'Install the packages needed for building and deploying'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Install dependencies from build_linux.sh
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ${{ github.workspace }}/deps/build/destdir
|
||||
sudo env "ORCA_UPDATER_SIG_KEY=$ORCA_UPDATER_SIG_KEY" ./build_linux.sh -ur
|
||||
sudo chown $USER -R ./
|
||||
18
.github/dependabot.yml
vendored
@@ -1,18 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
# Only care about major updates to github actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
ignore: # Only suggest major updates for built-in actions
|
||||
- dependency-name: "github/*"
|
||||
update-types: ["version-update:semver-patch", "version-update:semver-minor"]
|
||||
- dependency-name: "actions/*"
|
||||
update-types: ["version-update:semver-patch", "version-update:semver-minor"]
|
||||
# Docker dependencies
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
# no support for c/cpp
|
||||
27
.github/pull_request_template.md
vendored
@@ -1,27 +0,0 @@
|
||||
# Description
|
||||
|
||||
<!--
|
||||
> Please provide a summary of the changes made in this PR. Include details such as:
|
||||
> * What issue does this PR address or fix?
|
||||
> * What new features or enhancements does this PR introduce?
|
||||
> * Are there any breaking changes or dependencies that need to be considered?
|
||||
-->
|
||||
|
||||
# Screenshots/Recordings/Graphs
|
||||
|
||||
<!--
|
||||
> Please attach relevant screenshots to showcase the UI changes.
|
||||
> Please attach images that can help explain the changes.
|
||||
-->
|
||||
|
||||
## Tests
|
||||
|
||||
<!--
|
||||
> Please describe the tests that you have conducted to verify the changes made in this PR.
|
||||
-->
|
||||
|
||||
<!--
|
||||
> A guide for users on how to download the artifacts from this PR.
|
||||
-->
|
||||
|
||||
[How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
|
||||
26
.github/workflows/assign.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Assign Issue
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 0 * * *
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
assign:
|
||||
permissions:
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Assign the user or unassign stale assignments
|
||||
# Note: v3.0.0 is broken (dist/index.mjs vs action.yml expects index.js)
|
||||
# See: https://github.com/takanome-dev/assign-issue-action/issues/426
|
||||
uses: takanome-dev/assign-issue-action@v2.2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
maintainers: 'noisyfox,softfever'
|
||||
days_until_unassign: 30
|
||||
block_assignment: false
|
||||
reminder_days: 7
|
||||
max_assignments: 12
|
||||
31
.github/workflows/auto-close-duplicates.yml
vendored
@@ -1,31 +0,0 @@
|
||||
name: Auto-close duplicate issues
|
||||
description: Auto-closes issues that are duplicates of existing issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 9 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
auto-close-duplicates:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Auto-close duplicate issues
|
||||
run: bun run scripts/auto-close-duplicates.ts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
|
||||
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
|
||||
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}
|
||||
@@ -1,44 +0,0 @@
|
||||
name: Backfill Duplicate Comments
|
||||
description: Triggers duplicate detection for old issues that don't have duplicate comments
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
days_back:
|
||||
description: 'How many days back to look for old issues'
|
||||
required: false
|
||||
default: '90'
|
||||
type: string
|
||||
dry_run:
|
||||
description: 'Dry run mode (true to only log what would be done)'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
|
||||
jobs:
|
||||
backfill-duplicate-comments:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Backfill duplicate comments
|
||||
run: bun run scripts/backfill-duplicate-comments.ts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DAYS_BACK: ${{ inputs.days_back }}
|
||||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
269
.github/workflows/build_all.yml
vendored
@@ -1,269 +0,0 @@
|
||||
name: Build all
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
- belt-printer
|
||||
paths:
|
||||
- 'deps/**'
|
||||
- 'src/**'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'version.inc'
|
||||
- 'localization/**'
|
||||
- 'resources/**'
|
||||
- ".github/workflows/build_*.yml"
|
||||
- 'scripts/flatpak/**'
|
||||
- 'scripts/msix/**'
|
||||
- 'tests/**'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
paths:
|
||||
- 'deps/**'
|
||||
- 'deps_src/**'
|
||||
- 'src/**'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'version.inc'
|
||||
- ".github/workflows/build_*.yml"
|
||||
- 'build_linux.sh'
|
||||
- 'build_release_vs.bat'
|
||||
- 'build_release_vs2022.bat'
|
||||
- 'build_release_macos.sh'
|
||||
- 'scripts/flatpak/**'
|
||||
- 'scripts/msix/**'
|
||||
- 'tests/**'
|
||||
|
||||
|
||||
schedule:
|
||||
- cron: '0 17 * * *' # run once a day at 1 AM Singapore time (UTC+8)
|
||||
|
||||
workflow_dispatch: # allows for manual dispatch
|
||||
inputs:
|
||||
build-deps-only:
|
||||
description: 'Only build dependencies (bypasses caching)'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# Build both arches on every event (PRs included), through the same
|
||||
# build_check_cache -> build_deps -> build_orca chain (the AppImage).
|
||||
# aarch64 always uses the GitHub-hosted arm runner (there is no arm
|
||||
# self-hosted server). amd64's empty arch is load-bearing: it keeps the
|
||||
# historical 'linux-clang' deps cache key and the unsuffixed asset names.
|
||||
matrix:
|
||||
include:
|
||||
- arch: ""
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }}
|
||||
- arch: "aarch64"
|
||||
os: ubuntu-24.04-arm
|
||||
# Don't run scheduled builds on forks:
|
||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_check_cache.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
arch: ${{ matrix.arch }}
|
||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||
secrets: inherit
|
||||
build_windows:
|
||||
name: Build Windows ${{ matrix.arch }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
os: windows-latest
|
||||
- arch: arm64
|
||||
os: windows-11-arm
|
||||
# Don't run scheduled builds on forks:
|
||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_check_cache.yml
|
||||
with:
|
||||
# Self-hosted runner is x64-only; ARM64 always uses the GitHub-hosted runner.
|
||||
os: ${{ (matrix.arch == 'x64' && vars.SELF_HOSTED) && 'orca-win-server' || matrix.os }}
|
||||
arch: ${{ matrix.arch }}
|
||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||
force-build: ${{ github.event_name == 'schedule' }}
|
||||
secrets: inherit
|
||||
build_macos_arch:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch:
|
||||
- arm64
|
||||
- x86_64
|
||||
# Don't run scheduled builds on forks:
|
||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_check_cache.yml
|
||||
with:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
arch: ${{ matrix.arch }}
|
||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||
force-build: ${{ github.event_name == 'schedule' }}
|
||||
secrets: inherit
|
||||
build_macos_universal:
|
||||
name: Build macOS Universal
|
||||
needs: build_macos_arch
|
||||
if: ${{ !cancelled() && needs.build_macos_arch.result == 'success' && !inputs.build-deps-only && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
uses: ./.github/workflows/build_orca.yml
|
||||
with:
|
||||
os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }}
|
||||
arch: universal
|
||||
macos-combine-only: true
|
||||
secrets: inherit
|
||||
unit_tests:
|
||||
name: Unit Tests
|
||||
# Tests are built on the aarch64 leg by default (faster GitHub arm runner),
|
||||
# so run them there; self-hosted builds them on the amd64 server instead.
|
||||
runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04-arm' }}
|
||||
needs: build_linux
|
||||
if: ${{ !cancelled() && success() }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
scripts
|
||||
tests
|
||||
- name: Apt-Install Dependencies
|
||||
if: ${{ !vars.SELF_HOSTED }}
|
||||
uses: ./.github/actions/apt-install-deps
|
||||
- name: Restore Test Artifact
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ github.sha }}-tests
|
||||
- uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||
useCloudCache: true
|
||||
- name: Unpackage and Run Unit Tests
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
tar -xvf build_tests.tar
|
||||
scripts/run_unit_tests.sh
|
||||
- name: Upload Test Logs
|
||||
uses: actions/upload-artifact@v7
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: unit-test-logs
|
||||
path: build/tests/**/*.log
|
||||
- name: Publish Test Results
|
||||
if: always()
|
||||
uses: EnricoMi/publish-unit-test-result-action@v2
|
||||
with:
|
||||
files: "ctest_results.xml"
|
||||
- name: Delete Test Artifact
|
||||
if: success()
|
||||
uses: geekyeggo/delete-artifact@v6
|
||||
with:
|
||||
name: ${{ github.sha }}-tests
|
||||
flatpak:
|
||||
name: "Flatpak"
|
||||
container:
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-50
|
||||
options: --privileged
|
||||
volumes:
|
||||
- /usr/local/lib/android:/usr/local/lib/android
|
||||
- /usr/share/dotnet:/usr/share/dotnet
|
||||
- /opt/ghc:/opt/ghc1
|
||||
- /usr/local/share/boost:/usr/local/share/boost1
|
||||
- /opt/hostedtoolcache:/opt/hostedtoolcache1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
variant:
|
||||
- arch: x86_64
|
||||
runner: ubuntu-24.04
|
||||
- arch: aarch64
|
||||
runner: ubuntu-24.04-arm
|
||||
# Don't run scheduled builds on forks; skip entirely on self-hosted runners
|
||||
if: ${{ !cancelled() && !vars.SELF_HOSTED && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||
|
||||
runs-on: ${{ matrix.variant.runner }}
|
||||
env:
|
||||
date:
|
||||
ver:
|
||||
ver_pure:
|
||||
# Belt-printer nightlies share the main nightly release but carry a `_belt`
|
||||
# suffix so they never overwrite the main assets.
|
||||
nightly_suffix: ${{ github.ref == 'refs/heads/belt-printer' && '_belt' || '' }}
|
||||
steps:
|
||||
- name: "Remove unneeded stuff to free disk space"
|
||||
run:
|
||||
rm -rf /usr/local/lib/android/* /usr/share/dotnet/* /opt/ghc1/* "/usr/local/share/boost1/*" /opt/hostedtoolcache1/*
|
||||
- uses: actions/checkout@v7
|
||||
- name: Get the version and date
|
||||
run: |
|
||||
ver_pure=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
ver="PR-${{ github.event.number }}"
|
||||
git_commit_hash="${{ github.event.pull_request.head.sha }}"
|
||||
else
|
||||
ver=V$ver_pure
|
||||
git_commit_hash="${{ github.sha }}"
|
||||
fi
|
||||
echo "ver=$ver" >> $GITHUB_ENV
|
||||
echo "ver_pure=$ver_pure" >> $GITHUB_ENV
|
||||
echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV
|
||||
echo "git_commit_hash=$git_commit_hash" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
# Manage flatpak-builder cache externally so PRs restore but never upload
|
||||
- name: Restore flatpak-builder cache
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: .flatpak-builder
|
||||
key: flatpak-builder-${{ matrix.variant.arch }}-${{ github.event.pull_request.base.sha }}
|
||||
restore-keys: flatpak-builder-${{ matrix.variant.arch }}-
|
||||
- name: Save/restore flatpak-builder cache
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: .flatpak-builder
|
||||
key: flatpak-builder-${{ matrix.variant.arch }}-${{ github.sha }}
|
||||
restore-keys: flatpak-builder-${{ matrix.variant.arch }}-
|
||||
- name: Disable debug info for faster CI builds
|
||||
run: |
|
||||
sed -i '/^build-options:/a\ no-debuginfo: true\n strip: true' \
|
||||
scripts/flatpak/com.orcaslicer.OrcaSlicer.yml
|
||||
shell: bash
|
||||
- name: Inject git commit hash into Flatpak manifest
|
||||
run: |
|
||||
sed -i "/name: OrcaSlicer/{n;s|buildsystem: simple|buildsystem: simple\n build-options:\n env:\n git_commit_hash: \"$git_commit_hash\"|}" \
|
||||
scripts/flatpak/com.orcaslicer.OrcaSlicer.yml
|
||||
shell: bash
|
||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@master
|
||||
with:
|
||||
bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||
manifest-path: scripts/flatpak/com.orcaslicer.OrcaSlicer.yml
|
||||
cache: false
|
||||
arch: ${{ matrix.variant.arch }}
|
||||
upload-artifact: false
|
||||
- name: Upload artifacts Flatpak
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||
path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
|
||||
- name: Deploy Flatpak to nightly release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer')
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: /__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||
asset_name: OrcaSlicer-Linux-flatpak_nightly${{ env.nightly_suffix }}_${{ matrix.variant.arch }}.flatpak
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||
67
.github/workflows/build_check_cache.yml
vendored
@@ -1,67 +0,0 @@
|
||||
name: Check Cache
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
arch:
|
||||
required: false
|
||||
type: string
|
||||
build-deps-only:
|
||||
required: false
|
||||
type: boolean
|
||||
force-build:
|
||||
required: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
check_cache: # determines if there is a cache and outputs variables used in caching process
|
||||
name: Check Cache
|
||||
runs-on: ${{ inputs.os }}
|
||||
outputs:
|
||||
cache-key: ${{ steps.set_outputs.outputs.cache-key }}
|
||||
cache-path: ${{ steps.set_outputs.outputs.cache-path }}
|
||||
valid-cache: ${{ steps.cache_deps.outputs.cache-hit }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
lfs: 'false'
|
||||
|
||||
- name: set outputs
|
||||
id: set_outputs
|
||||
env:
|
||||
# Keep macOS/Windows cache keys architecture-specific. amd64 Linux passes
|
||||
# no arch (key stays 'linux-clang', preserving the existing cache);
|
||||
# aarch64 gets its own 'linux-clang-aarch64' key.
|
||||
cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && format('windows-{0}', inputs.arch) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }}
|
||||
# ARM64 builds use the build-arm64 tree (see build_release_vs.bat); x64/other use build.
|
||||
dep-folder-name: ${{ runner.os == 'macOS' && format('/{0}', inputs.arch) || (runner.os == 'Windows' && inputs.arch == 'arm64') && '-arm64/OrcaSlicer_dep' || '/OrcaSlicer_dep' }}
|
||||
output-cmd: ${{ runner.os == 'Windows' && '$env:GITHUB_OUTPUT' || '"$GITHUB_OUTPUT"'}}
|
||||
run: |
|
||||
echo cache-key=${{ env.cache-os }}-cache-orcaslicer_deps-build-${{ hashFiles('deps/**') }} >> ${{ env.output-cmd }}
|
||||
echo cache-path=${{ github.workspace }}/deps/build${{ env.dep-folder-name }} >> ${{ env.output-cmd }}
|
||||
|
||||
- name: load cache
|
||||
id: cache_deps
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ steps.set_outputs.outputs.cache-path }}
|
||||
key: ${{ steps.set_outputs.outputs.cache-key }}
|
||||
lookup-only: true
|
||||
|
||||
build_deps: # call next step
|
||||
name: Build Deps
|
||||
needs: [check_cache]
|
||||
uses: ./.github/workflows/build_deps.yml
|
||||
with:
|
||||
cache-key: ${{ needs.check_cache.outputs.cache-key }}
|
||||
cache-path: ${{ needs.check_cache.outputs.cache-path }}
|
||||
valid-cache: ${{ needs.check_cache.outputs.valid-cache == 'true' }}
|
||||
os: ${{ inputs.os }}
|
||||
arch: ${{ inputs.arch }}
|
||||
build-deps-only: ${{ inputs.build-deps-only }}
|
||||
force-build: ${{ inputs.force-build }}
|
||||
secrets: inherit
|
||||
207
.github/workflows/build_deps.yml
vendored
@@ -1,207 +0,0 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
cache-key:
|
||||
required: true
|
||||
type: string
|
||||
cache-path:
|
||||
required: true
|
||||
type: string
|
||||
valid-cache:
|
||||
required: true
|
||||
type: boolean
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
arch:
|
||||
required: false
|
||||
type: string
|
||||
build-deps-only:
|
||||
required: false
|
||||
type: boolean
|
||||
force-build:
|
||||
required: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build_deps:
|
||||
name: Build Deps
|
||||
if: ${{ !cancelled() && (inputs.build-deps-only || inputs.force-build || inputs.valid-cache != true) }}
|
||||
runs-on: ${{ inputs.os }}
|
||||
env:
|
||||
date:
|
||||
steps:
|
||||
|
||||
# Setup the environment
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
lfs: 'false'
|
||||
|
||||
- name: load cached deps
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ inputs.cache-path }}
|
||||
key: ${{ inputs.cache-key }}
|
||||
|
||||
- uses: lukka/get-cmake@latest
|
||||
# The windows-11-arm runner needs CMake <= 3.31 (handled in the next step).
|
||||
if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }}
|
||||
with:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||
useCloudCache: true
|
||||
|
||||
- name: Install CMake 3.31.x (Windows ARM64)
|
||||
# windows-11-arm ships CMake 4.x, which removed pre-3.5 policy
|
||||
# compatibility AND has incomplete ASM_ARMASM linker modules
|
||||
# (breaks Boost.Context on ARM64). Pin to the last 3.x release.
|
||||
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ver = "3.31.6"
|
||||
$url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip"
|
||||
Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip"
|
||||
Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force
|
||||
$cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin"
|
||||
if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" }
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin
|
||||
|
||||
- name: setup dev on Windows
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Get the date on Ubuntu and macOS
|
||||
if: runner.os != 'Windows'
|
||||
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Get the date on Windows
|
||||
if: runner.os == 'Windows'
|
||||
run: echo "date=$(Get-Date -Format 'yyyyMMdd')" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
shell: pwsh
|
||||
|
||||
|
||||
- name: Install MSYS2 (clangarm64) with GMP/MPFR and LLVM tools
|
||||
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANGARM64
|
||||
update: true
|
||||
install: >-
|
||||
mingw-w64-clang-aarch64-gmp
|
||||
mingw-w64-clang-aarch64-mpfr
|
||||
mingw-w64-clang-aarch64-llvm
|
||||
|
||||
- name: Stage ARM64 GMP/MPFR (no prebuilt blobs exist for win-arm64)
|
||||
# GMP/MPFR ship prebuilt x64/x86 blobs in-tree but none for ARM64.
|
||||
# Pull them from MSYS2 clangarm64 and generate MSVC import libs via
|
||||
# llvm-dlltool, then stage into deps/{GMP,MPFR}/.../win-arm64 where the
|
||||
# MSVC branch of GMP.cmake/MPFR.cmake copies them into the dep prefix.
|
||||
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BIN=/clangarm64/bin
|
||||
REPO=$(cygpath -u "$GITHUB_WORKSPACE")
|
||||
|
||||
make_import_lib() {
|
||||
local dll="$1"; local lib="$2"; local def="/tmp/${dll%.dll}.def"
|
||||
echo "EXPORTS" > "$def"
|
||||
llvm-readobj --coff-exports "$BIN/$dll" | awk '/Name: /{print $2}' >> "$def"
|
||||
llvm-dlltool -m arm64 -D "$dll" -d "$def" -l "$BIN/$lib"
|
||||
}
|
||||
|
||||
make_import_lib libgmp-10.dll libgmp-10.lib
|
||||
|
||||
# MPFR 4.x ships as libmpfr-6.dll; rename to libmpfr-4 BEFORE generating
|
||||
# the import lib so the baked-in runtime DLL name is correct.
|
||||
MPFR_DLL=$(ls $BIN/libmpfr-*.dll | head -1 | xargs basename)
|
||||
if [ "$MPFR_DLL" != "libmpfr-4.dll" ]; then cp "$BIN/$MPFR_DLL" "$BIN/libmpfr-4.dll"; fi
|
||||
make_import_lib libmpfr-4.dll libmpfr-4.lib
|
||||
|
||||
mkdir -p $REPO/deps/GMP/gmp/lib/win-arm64 $REPO/deps/MPFR/mpfr/lib/win-arm64
|
||||
cp $BIN/libgmp-10.dll $BIN/libgmp-10.lib $REPO/deps/GMP/gmp/lib/win-arm64/
|
||||
cp $BIN/libmpfr-4.dll $BIN/libmpfr-4.lib $REPO/deps/MPFR/mpfr/lib/win-arm64/
|
||||
cp /clangarm64/include/gmp.h $REPO/deps/GMP/gmp/include/
|
||||
cp /clangarm64/include/mpfr.h $REPO/deps/MPFR/mpfr/include/ || true
|
||||
|
||||
# Build Dependencies
|
||||
- name: Build on Windows
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
if (-not "${{ vars.SELF_HOSTED }}") {
|
||||
choco install strawberryperl
|
||||
}
|
||||
$arch = "${{ inputs.arch }}"
|
||||
if ($arch -eq "arm64") {
|
||||
.\build_release_vs.bat deps arm64
|
||||
.\build_release_vs.bat pack arm64
|
||||
} else {
|
||||
.\build_release_vs.bat deps
|
||||
.\build_release_vs.bat pack
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
- name: Build on Mac ${{ inputs.arch }}
|
||||
if: runner.os == 'macOS'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
if [ -z "${{ vars.SELF_HOSTED }}" ]; then
|
||||
brew install automake texinfo libtool
|
||||
fi
|
||||
./build_release_macos.sh -dx ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15
|
||||
(cd "${{ github.workspace }}/deps/build/${{ inputs.arch }}" && \
|
||||
find . -mindepth 1 -maxdepth 1 ! -name 'OrcaSlicer_dep' -exec rm -rf {} +)
|
||||
|
||||
|
||||
- name: Apt-Install Dependencies
|
||||
if: runner.os == 'Linux' && !vars.SELF_HOSTED
|
||||
uses: ./.github/actions/apt-install-deps
|
||||
|
||||
- name: Build on Ubuntu
|
||||
if: runner.os == 'Linux'
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
mkdir -p ${{ github.workspace }}/deps/build/destdir
|
||||
./build_linux.sh -drlL
|
||||
cd deps/build
|
||||
tar -czvf OrcaSlicer_dep_ubuntu_$(date +"%Y%m%d").tar.gz destdir
|
||||
|
||||
|
||||
# Upload Artifacts
|
||||
# - name: Upload Mac ${{ inputs.arch }} artifacts
|
||||
# if: runner.os == 'macOS'
|
||||
# uses: actions/upload-artifact@v6
|
||||
# with:
|
||||
# name: OrcaSlicer_dep_mac_${{ env.date }}
|
||||
# path: ${{ github.workspace }}/deps/build/OrcaSlicer_dep*.tar.gz
|
||||
|
||||
# - name: Upload Windows artifacts
|
||||
# if: runner.os == 'Windows'
|
||||
# uses: actions/upload-artifact@v6
|
||||
# with:
|
||||
# name: OrcaSlicer_dep_win64_${{ env.date }}
|
||||
# path: ${{ github.workspace }}/deps/build/OrcaSlicer_dep*.zip
|
||||
|
||||
# - name: Upload Ubuntu artifacts
|
||||
# if: runner.os == 'Linux' && !env.ACT
|
||||
# env:
|
||||
# ubuntu-ver: '2404'
|
||||
# uses: actions/upload-artifact@v6
|
||||
# with:
|
||||
# name: OrcaSlicer_dep_ubuntu_${{ env.ubuntu-ver }}_${{ env.date }}
|
||||
# path: ${{ github.workspace }}/deps/build/OrcaSlicer_dep_ubuntu_*.tar.gz
|
||||
|
||||
build_orca:
|
||||
name: Build OrcaSlicer
|
||||
needs: [build_deps]
|
||||
if: ${{ !cancelled() && !inputs.build-deps-only && (inputs.force-build || (inputs.valid-cache == true && needs.build_deps.result == 'skipped') || (inputs.valid-cache != true && success())) }}
|
||||
uses: ./.github/workflows/build_orca.yml
|
||||
with:
|
||||
cache-key: ${{ inputs.cache-key }}
|
||||
cache-path: ${{ inputs.cache-path }}
|
||||
os: ${{ inputs.os }}
|
||||
arch: ${{ inputs.arch }}
|
||||
secrets: inherit
|
||||
552
.github/workflows/build_orca.yml
vendored
@@ -1,552 +0,0 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
cache-key:
|
||||
required: false
|
||||
type: string
|
||||
cache-path:
|
||||
required: false
|
||||
type: string
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
arch:
|
||||
required: false
|
||||
type: string
|
||||
macos-combine-only:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_orca:
|
||||
name: Build OrcaSlicer
|
||||
runs-on: ${{ inputs.os }}
|
||||
env:
|
||||
date:
|
||||
ver:
|
||||
ver_pure:
|
||||
ubuntu-ver: '2404'
|
||||
ubuntu-ver-str: '_Ubuntu2404'
|
||||
ORCA_UPDATER_SIG_KEY: ${{ secrets.ORCA_UPDATER_SIG_KEY }}
|
||||
# Branches whose builds are published to the nightly release. The
|
||||
# belt-printer branch ships alongside main but its assets carry a `_belt`
|
||||
# suffix (nightly_suffix) so they never overwrite the main nightly assets.
|
||||
deploy_nightly: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' }}
|
||||
nightly_suffix: ${{ github.ref == 'refs/heads/belt-printer' && '_belt' || '' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
lfs: 'false'
|
||||
|
||||
- name: load cached deps
|
||||
if: ${{ !(runner.os == 'macOS' && inputs.macos-combine-only) }}
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ${{ inputs.cache-path }}
|
||||
key: ${{ inputs.cache-key }}
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- uses: lukka/get-cmake@latest
|
||||
# The windows-11-arm runner needs CMake <= 3.31 (handled in the next step).
|
||||
if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }}
|
||||
with:
|
||||
cmakeVersion: "~4.3.0" # use most recent 4.3.x version
|
||||
useLocalCache: true # <--= Use the local cache (default is 'false').
|
||||
useCloudCache: true
|
||||
|
||||
- name: Install CMake 3.31.x (Windows ARM64)
|
||||
# windows-11-arm ships CMake 4.x, which removed pre-3.5 policy
|
||||
# compatibility AND has incomplete ASM_ARMASM linker modules
|
||||
# (breaks Boost.Context on ARM64). Pin to the last 3.x release.
|
||||
if: runner.os == 'Windows' && inputs.arch == 'arm64'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ver = "3.31.6"
|
||||
$url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip"
|
||||
Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip"
|
||||
Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force
|
||||
$cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin"
|
||||
if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" }
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin
|
||||
|
||||
- name: Get the version and date on Ubuntu and macOS
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
ver_pure=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
ver="PR-${{ github.event.number }}"
|
||||
git_commit_hash="${{ github.event.pull_request.head.sha }}"
|
||||
else
|
||||
ver=V$ver_pure
|
||||
git_commit_hash=""
|
||||
fi
|
||||
echo "ver=$ver" >> $GITHUB_ENV
|
||||
echo "ver_pure=$ver_pure" >> $GITHUB_ENV
|
||||
echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV
|
||||
echo "git_commit_hash=$git_commit_hash" >> $GITHUB_ENV
|
||||
# Per-arch Linux AppImage naming: amd64 keeps the historical unsuffixed
|
||||
# name (arch_suffix empty). Unused on macOS/Windows.
|
||||
if [ '${{ inputs.arch }}' = 'aarch64' ]; then
|
||||
echo "arch_suffix=_aarch64" >> $GITHUB_ENV
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Get the version and date on Windows
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
$date = Get-Date -Format 'yyyyMMdd'
|
||||
$ref = "${{ github.ref }}"
|
||||
$eventName = "${{ github.event_name }}"
|
||||
$prNumber = "${{ github.event.number }}"
|
||||
|
||||
if ($eventName -eq 'pull_request') {
|
||||
$ver = "PR" + $prNumber
|
||||
$git_commit_hash = "${{ github.event.pull_request.head.sha }}"
|
||||
} else {
|
||||
$versionContent = Get-Content version.inc -Raw
|
||||
if ($versionContent -match 'set\(SoftFever_VERSION "(.*?)"\)') {
|
||||
$ver = $matches[1]
|
||||
}
|
||||
$ver = "V$ver"
|
||||
$git_commit_hash = ""
|
||||
}
|
||||
|
||||
echo "ver=$ver" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
echo "date=$date" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
echo "git_commit_hash=$git_commit_hash" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
echo "date: ${{ env.date }} version: ${{ env.ver }}"
|
||||
shell: pwsh
|
||||
|
||||
# Mac
|
||||
- name: Install tools mac
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only
|
||||
run: |
|
||||
if [ -z "${{ vars.SELF_HOSTED }}" ]; then
|
||||
brew install libtool
|
||||
brew list
|
||||
fi
|
||||
mkdir -p ${{ github.workspace }}/deps/build/${{ inputs.arch }}
|
||||
|
||||
- name: Free disk space
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||
run: |
|
||||
df -hI /dev/disk3s1s1
|
||||
sudo find /Applications -maxdepth 1 -type d -name "Xcode_*.app" ! -name "Xcode_15.4.app" -exec rm -rf {} +
|
||||
sudo rm -rf ~/Library/Developer/CoreSimulator/Caches/*
|
||||
df -hI /dev/disk3s1s1
|
||||
|
||||
- name: Build slicer mac
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
./build_release_macos.sh -s -n -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15
|
||||
|
||||
- name: Pack macOS app bundle ${{ inputs.arch }}
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
tar -czvf OrcaSlicer_Mac_bundle_${{ inputs.arch }}_${{ github.sha }}.tar.gz -C build/${{ inputs.arch }} OrcaSlicer
|
||||
|
||||
- name: Upload macOS app bundle ${{ inputs.arch }}
|
||||
if: runner.os == 'macOS' && !inputs.macos-combine-only
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Mac_bundle_${{ inputs.arch }}_${{ github.sha }}
|
||||
path: ${{ github.workspace }}/OrcaSlicer_Mac_bundle_${{ inputs.arch }}_${{ github.sha }}.tar.gz
|
||||
|
||||
- name: Download macOS app bundles
|
||||
if: runner.os == 'macOS' && inputs.macos-combine-only
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: OrcaSlicer_Mac_bundle_*_${{ github.sha }}
|
||||
path: ${{ github.workspace }}/mac_bundles
|
||||
|
||||
- name: Extract macOS app bundles
|
||||
if: runner.os == 'macOS' && inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
mkdir -p build/arm64 build/x86_64
|
||||
arm_bundle=$(find "${{ github.workspace }}/mac_bundles/OrcaSlicer_Mac_bundle_arm64_${{ github.sha }}" -name '*.tar.gz' -print -quit)
|
||||
x86_bundle=$(find "${{ github.workspace }}/mac_bundles/OrcaSlicer_Mac_bundle_x86_64_${{ github.sha }}" -name '*.tar.gz' -print -quit)
|
||||
tar -xzvf "$arm_bundle" -C "${{ github.workspace }}/build/arm64"
|
||||
tar -xzvf "$x86_bundle" -C "${{ github.workspace }}/build/x86_64"
|
||||
|
||||
- name: Build universal mac app bundle
|
||||
if: runner.os == 'macOS' && inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
./build_release_macos.sh -u -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a universal -t 10.15
|
||||
|
||||
# Thanks to RaySajuuk, it's working now
|
||||
- name: Sign app and notary
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/belt-printer' || startsWith(github.ref, 'refs/heads/release/')) && runner.os == 'macOS' && inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
env:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
CERTIFICATE_ID: ${{ secrets.MACOS_CERTIFICATE_ID }}
|
||||
run: |
|
||||
# Load the `retry` helper (retries flaky commands such as `hdiutil create`).
|
||||
source ${{ github.workspace }}/scripts/retry.sh
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
|
||||
# Set the temporary keychain as the default to prevent codesign from accessing the locked login keychain
|
||||
security default-keychain -s "$KEYCHAIN_PATH"
|
||||
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $P12_PASSWORD $KEYCHAIN_PATH
|
||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app
|
||||
# Sign OrcaSlicer_profile_validator.app if it exists
|
||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app
|
||||
fi
|
||||
|
||||
# Create main OrcaSlicer DMG without the profile validator helper
|
||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
|
||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/*
|
||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/
|
||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/Applications
|
||||
retry hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
|
||||
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg
|
||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/*
|
||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/
|
||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/Applications
|
||||
retry hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
fi
|
||||
|
||||
# Notarize main DMG
|
||||
xcrun notarytool submit "OrcaSlicer_Mac_universal_${{ env.ver }}.dmg" --apple-id "${{ secrets.APPLE_DEV_ACCOUNT }}" --team-id "${{ secrets.TEAM_ID }}" --password "${{ secrets.APP_PWD }}" --wait
|
||||
xcrun stapler staple OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
|
||||
# Notarize profile validator DMG if it exists
|
||||
if [ -f "OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg" ]; then
|
||||
xcrun notarytool submit "OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg" --apple-id "${{ secrets.APPLE_DEV_ACCOUNT }}" --team-id "${{ secrets.TEAM_ID }}" --password "${{ secrets.APP_PWD }}" --wait
|
||||
xcrun stapler staple OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
fi
|
||||
|
||||
- name: Create DMG without notary
|
||||
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/belt-printer' && runner.os == 'macOS' && inputs.macos-combine-only
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
# Load the `retry` helper (retries flaky commands such as `hdiutil create`).
|
||||
source ${{ github.workspace }}/scripts/retry.sh
|
||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
|
||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/*
|
||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/
|
||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/Applications
|
||||
retry hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
|
||||
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg
|
||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/*
|
||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/
|
||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/Applications
|
||||
retry hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
fi
|
||||
|
||||
# Delete the per-arch bundles only after signing/DMG creation succeeded, so a
|
||||
# failed run keeps them available for a re-run instead of forcing a full rebuild.
|
||||
- name: Delete intermediate per-arch artifacts
|
||||
if: success() && runner.os == 'macOS' && inputs.macos-combine-only
|
||||
uses: geekyeggo/delete-artifact@v6
|
||||
with:
|
||||
name: |
|
||||
OrcaSlicer_Mac_bundle_arm64_${{ github.sha }}
|
||||
OrcaSlicer_Mac_bundle_x86_64_${{ github.sha }}
|
||||
|
||||
- name: Upload artifacts mac
|
||||
if: runner.os == 'macOS' && inputs.macos-combine-only
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Mac_universal_${{ env.ver }}
|
||||
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
|
||||
- name: Upload OrcaSlicer_profile_validator DMG mac
|
||||
if: runner.os == 'macOS' && inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_profile_validator_Mac_universal_DMG_${{ env.ver }}
|
||||
path: ${{ github.workspace }}/OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Deploy Mac release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'macOS' && inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||
asset_name: OrcaSlicer_Mac_universal_nightly${{ env.nightly_suffix }}.dmg
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||
|
||||
- name: Deploy Mac OrcaSlicer_profile_validator DMG release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'macOS' && inputs.macos-combine-only && !vars.SELF_HOSTED
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||
asset_name: OrcaSlicer_profile_validator_Mac_universal_nightly.dmg
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1
|
||||
|
||||
# Windows
|
||||
- name: Set Windows build variables
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
if ("${{ inputs.arch }}" -eq "arm64") {
|
||||
"BUILD_DIR=build-arm64" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
"ARCH_SUFFIX=_arm64" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
} else {
|
||||
"BUILD_DIR=build" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
"ARCH_SUFFIX=_x64" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
|
||||
}
|
||||
|
||||
- name: setup MSVC
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v3
|
||||
|
||||
- name: Install nsis
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
run: |
|
||||
dir "C:/Program Files (x86)/Windows Kits/10/Include"
|
||||
choco install nsis
|
||||
|
||||
- name: Build slicer Win
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{ github.workspace }}
|
||||
# Orca: Removed Netfabb STL fixing service support in favor of CGAL.
|
||||
# env:
|
||||
# WindowsSdkDir: 'C:\Program Files (x86)\Windows Kits\10\'
|
||||
# WindowsSDKVersion: '10.0.26100.0\'
|
||||
run: |
|
||||
$arch = "${{ inputs.arch }}"
|
||||
if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 } else { .\build_release_vs.bat slicer }
|
||||
shell: pwsh
|
||||
|
||||
# NSIS is x86-only; it runs (and the installer it emits runs) under ARM64's
|
||||
# x86 emulation, packaging the native arm64 payload from build-arm64.
|
||||
- name: Create installer Win
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
cpack -G NSIS
|
||||
|
||||
- name: Pack app
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }}
|
||||
shell: cmd
|
||||
run: '"C:/Program Files/7-Zip/7z.exe" a -tzip OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer'
|
||||
|
||||
- name: Pack PDB
|
||||
if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED
|
||||
working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }}/src/Release
|
||||
shell: cmd
|
||||
run: '"C:/Program Files/7-Zip/7z.exe" a -m0=lzma2 -mx9 Debug_PDB_${{ env.ver }}_for_developers_only.7z *.pdb'
|
||||
|
||||
- name: Upload artifacts Win zip
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable
|
||||
path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer
|
||||
|
||||
- name: Upload artifacts Win installer
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}
|
||||
path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer*.exe
|
||||
|
||||
- name: Upload artifacts Win PDB
|
||||
if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: PDB
|
||||
path: ${{ github.workspace }}/build/src/Release/Debug_PDB_${{ env.ver }}_for_developers_only.7z
|
||||
|
||||
- name: Upload OrcaSlicer_profile_validator Win
|
||||
if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_profile_validator_Windows_${{ env.ver }}
|
||||
path: ${{ github.workspace }}/build/src/Release/OrcaSlicer_profile_validator.exe
|
||||
|
||||
- name: Deploy Windows release portable
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip
|
||||
asset_name: OrcaSlicer_Windows${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}_portable.zip
|
||||
asset_content_type: application/x-zip-compressed
|
||||
max_releases: 1
|
||||
|
||||
- name: Deploy Windows release installer
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && env.deploy_nightly == 'true' && runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_Installer_${{ env.ver }}${{ env.ARCH_SUFFIX }}.exe
|
||||
asset_name: OrcaSlicer_Windows_Installer${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}.exe
|
||||
asset_content_type: application/x-msdownload
|
||||
max_releases: 1
|
||||
|
||||
- name: Deploy Windows OrcaSlicer_profile_validator release
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/build/src/Release/OrcaSlicer_profile_validator.exe
|
||||
asset_name: OrcaSlicer_profile_validator_Windows_nightly.exe
|
||||
asset_content_type: application/x-msdownload
|
||||
max_releases: 1
|
||||
|
||||
- name: Build MSIX Store package Win
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
working-directory: ${{ github.workspace }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
./scripts/msix/build_msix.ps1 `
|
||||
-InstallDir "${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer" `
|
||||
-OutputPath "${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }}.msix" `
|
||||
-Architecture "${{ inputs.arch }}" `
|
||||
-IdentityName "${{ vars.ORCA_MSIX_IDENTITY_NAME || 'OrcaSlicer.OrcaSlicer' }}" `
|
||||
-Publisher "${{ vars.ORCA_MSIX_PUBLISHER || 'CN=38F7EA55-C73B-4072-B3B2-C8E0EA15BB82' }}" `
|
||||
-PublisherDisplayName "${{ vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME || 'OrcaSlicer' }}"
|
||||
|
||||
- name: Upload artifacts Win MSIX
|
||||
if: runner.os == 'Windows' && !vars.SELF_HOSTED
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }}
|
||||
path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }}.msix
|
||||
|
||||
# Ubuntu
|
||||
- name: Apt-Install Dependencies
|
||||
if: runner.os == 'Linux' && !vars.SELF_HOSTED
|
||||
uses: ./.github/actions/apt-install-deps
|
||||
|
||||
# Tests must built at the same time as the slicer;
|
||||
# if you untangle them feel free to separate them here too
|
||||
- name: Build slicer and tests
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
run: |
|
||||
# Build + tar the unit tests (-t) only on the leg that runs them: the
|
||||
# aarch64 leg by default (faster GitHub arm runner), or amd64 when using
|
||||
# self-hosted runners (no arm self-hosted server). unit_tests downloads
|
||||
# this tarball. The profile validator is built with -s, so amd64 keeps it.
|
||||
tests=${{ (!vars.SELF_HOSTED && inputs.arch == 'aarch64') || (vars.SELF_HOSTED && inputs.arch != 'aarch64') }}
|
||||
if $tests; then flags=-istrlL; else flags=-isrlL; fi
|
||||
./build_linux.sh "$flags"
|
||||
./scripts/check_appimage_libs.sh ./build/package ./build/package/bin/orca-slicer
|
||||
appimage=./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage
|
||||
mv -n ./build/OrcaSlicer_Linux_V${{ env.ver_pure }}.AppImage "$appimage"
|
||||
chmod +x "$appimage"
|
||||
if $tests; then tar -cvpf build_tests.tar build/tests; fi
|
||||
|
||||
# Use tar because upload-artifacts won't always preserve directory structure
|
||||
# and doesn't preserve file permissions
|
||||
- name: Upload Test Artifact
|
||||
if: runner.os == 'Linux' && ((!vars.SELF_HOSTED && inputs.arch == 'aarch64') || (vars.SELF_HOSTED && inputs.arch != 'aarch64'))
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ github.sha }}-tests
|
||||
overwrite: true
|
||||
path: build_tests.tar
|
||||
retention-days: 5
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Run external slicer regression tests
|
||||
if: runner.os == 'Linux' && inputs.arch != 'aarch64'
|
||||
timeout-minutes: 20
|
||||
shell: bash
|
||||
run: |
|
||||
test_repo_dir="${{ runner.temp }}/orca-test-repo"
|
||||
rm -rf "$test_repo_dir"
|
||||
git clone --depth 1 https://github.com/OrcaSlicer/orca-test-repo.git "$test_repo_dir"
|
||||
python3 "$test_repo_dir/run_test.py" "${{ github.workspace }}/build/package/bin/orca-slicer"
|
||||
|
||||
- name: Build orca_custom_preset_tests
|
||||
if: github.ref == 'refs/heads/main' && runner.os == 'Linux' && !vars.SELF_HOSTED && inputs.arch != 'aarch64'
|
||||
working-directory: ${{ github.workspace }}/build/src/Release
|
||||
shell: bash
|
||||
run: |
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -g 1
|
||||
cd ${{ github.workspace }}/resources/profiles
|
||||
zip -r orca_custom_preset_tests.zip user/
|
||||
|
||||
- name: Upload artifacts Ubuntu
|
||||
if: ${{ ! env.ACT && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_Linux_ubuntu_${{ env.ubuntu-ver }}${{ env.arch_suffix }}_${{ env.ver }}
|
||||
path: "./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage"
|
||||
|
||||
- name: Upload OrcaSlicer_profile_validator Ubuntu
|
||||
if: ${{ ! env.ACT && runner.os == 'Linux' && !vars.SELF_HOSTED && inputs.arch != 'aarch64' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: OrcaSlicer_profile_validator_Linux_ubuntu_${{ env.ubuntu-ver }}_${{ env.ver }}
|
||||
path: './build/src/Release/OrcaSlicer_profile_validator'
|
||||
|
||||
- name: Deploy Ubuntu release
|
||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && env.deploy_nightly == 'true' && runner.os == 'Linux' && !vars.SELF_HOSTED }}
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage
|
||||
asset_name: OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_nightly${{ env.nightly_suffix }}.AppImage
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||
- name: Deploy Ubuntu release
|
||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && github.ref == 'refs/heads/main' && runner.os == 'Linux' && !vars.SELF_HOSTED && inputs.arch != 'aarch64' }}
|
||||
uses: rickstaa/action-create-tag@v1
|
||||
with:
|
||||
tag: "nightly-builds"
|
||||
tag_exists_error: false
|
||||
force_push_tag: true
|
||||
message: "nightly-builds"
|
||||
|
||||
- name: Deploy Ubuntu OrcaSlicer_profile_validator release
|
||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && github.ref == 'refs/heads/main' && runner.os == 'Linux' && !vars.SELF_HOSTED && inputs.arch != 'aarch64' }}
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ./build/src/Release/OrcaSlicer_profile_validator
|
||||
asset_name: OrcaSlicer_profile_validator_Linux${{ env.ubuntu-ver-str }}_nightly
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1
|
||||
|
||||
- name: Deploy orca_custom_preset_tests
|
||||
if: ${{ github.repository == 'OrcaSlicer/OrcaSlicer' && ! env.ACT && github.ref == 'refs/heads/main' && runner.os == 'Linux' && !vars.SELF_HOSTED && inputs.arch != 'aarch64' }}
|
||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||
release_id: 137995723
|
||||
asset_path: ${{ github.workspace }}/resources/profiles/orca_custom_preset_tests.zip
|
||||
asset_name: orca_custom_preset_tests.zip
|
||||
asset_content_type: application/octet-stream
|
||||
max_releases: 1
|
||||
44
.github/workflows/check_locale.yml
vendored
@@ -1,44 +0,0 @@
|
||||
name: Check locale
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'localization/**'
|
||||
- ".github/workflows/check_locale.yml"
|
||||
|
||||
jobs:
|
||||
check_translation:
|
||||
name: Check translation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Install gettext
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gettext
|
||||
|
||||
# don't call ./run_gentext.sh as most translators never sync with main branch...
|
||||
- name: Check translation format
|
||||
run: |
|
||||
echo $PWD
|
||||
pot_file="./localization/i18n/OrcaSlicer.pot"
|
||||
for dir in ./localization/i18n/*/
|
||||
do
|
||||
dir=${dir%*/} # remove the trailing "/"
|
||||
lang=${dir##*/} # extract the language identifier
|
||||
|
||||
if [ -f "$dir/OrcaSlicer_${lang}.po" ]; then
|
||||
mkdir -p ./resources/i18n/${lang}/
|
||||
msgfmt --check-format -o ./resources/i18n/${lang}/OrcaSlicer.mo $dir/OrcaSlicer_${lang}.po
|
||||
# Check the exit status of the msgfmt command
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error encountered with msgfmt command for language ${lang}."
|
||||
exit 1 # Exit the script with an error status
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
229
.github/workflows/check_profiles.yml
vendored
@@ -1,229 +0,0 @@
|
||||
name: Check profiles
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'resources/profiles/**'
|
||||
- ".github/workflows/check_profiles.yml"
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
logLevel:
|
||||
description: 'Log level'
|
||||
required: true
|
||||
default: 'warning'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
|
||||
jobs:
|
||||
check_profiles:
|
||||
name: Check profiles
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Run extra JSON check
|
||||
id: extra_json_check
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +e
|
||||
python3 ./scripts/orca_extra_profile_check.py 2>&1 | tee ${{ runner.temp }}/extra_json_check.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
|
||||
# download
|
||||
- name: Download
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
curl -L -o OrcaSlicer_profile_validator https://github.com/OrcaSlicer/OrcaSlicer/releases/download/nightly-builds/OrcaSlicer_profile_validator_Linux_Ubuntu2404_nightly
|
||||
chmod +x ./OrcaSlicer_profile_validator
|
||||
|
||||
# Validate all system profiles.
|
||||
- name: validate system profiles
|
||||
id: validate_system
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 2>&1 | tee ${{ runner.temp }}/validate_system.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
# For now run filament subtype check only for BBL profiles until we fix other vendors' profiles.
|
||||
- name: validate filament subtype check for BBL profiles
|
||||
id: validate_filament_subtypes
|
||||
continue-on-error: true
|
||||
run: |
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p ${{ github.workspace }}/resources/profiles -l 2 -v BBL -f 2>&1 | tee ${{ runner.temp }}/validate_filament_subtypes.log
|
||||
exit ${PIPESTATUS[0]}
|
||||
|
||||
- name: validate custom presets
|
||||
id: validate_custom
|
||||
continue-on-error: true
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
fixtures_dir="${{ runner.temp }}/profile-fixtures"
|
||||
output_dir="${{ runner.temp }}/custom-preset-validation"
|
||||
combined_log="${{ runner.temp }}/validate_custom.log"
|
||||
summary="${output_dir}/summary.md"
|
||||
release_url="https://github.com/OrcaSlicer/OrcaSlicer-profile-validator/releases/download/fixture-archive"
|
||||
|
||||
rm -rf "${fixtures_dir}" "${output_dir}"
|
||||
mkdir -p "${fixtures_dir}" "${output_dir}"
|
||||
|
||||
curl -fsSL -o "${fixtures_dir}/manifest.json" "${release_url}/manifest.json"
|
||||
|
||||
MANIFEST_PATH="${fixtures_dir}/manifest.json" python3 <<'PY' > "${fixtures_dir}/fixtures.tsv"
|
||||
import json
|
||||
import os
|
||||
|
||||
with open(os.environ["MANIFEST_PATH"], encoding="utf-8") as fh:
|
||||
manifest = json.load(fh)
|
||||
|
||||
if isinstance(manifest, dict):
|
||||
entries = manifest.get("fixtures", [])
|
||||
else:
|
||||
entries = manifest
|
||||
|
||||
for entry in entries:
|
||||
version = entry.get("version", "")
|
||||
asset = entry.get("asset", "")
|
||||
sha256 = entry.get("asset_sha256", "")
|
||||
if not version or not asset:
|
||||
continue
|
||||
print(f"{version}\t{asset}\t{sha256}")
|
||||
PY
|
||||
|
||||
if [ ! -s "${fixtures_dir}/fixtures.tsv" ]; then
|
||||
echo "No custom preset fixtures found in ${release_url}/manifest.json" | tee "${combined_log}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
echo "## Custom Preset Fixture Validation"
|
||||
echo ""
|
||||
echo "| Version | Status | Log |"
|
||||
echo "| --- | --- | --- |"
|
||||
} > "${summary}"
|
||||
|
||||
status=0
|
||||
failed_logs=()
|
||||
|
||||
while IFS=$'\t' read -r version asset expected_sha256; do
|
||||
fixture_zip="${fixtures_dir}/${asset}"
|
||||
asset_url_name="$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "${asset}")"
|
||||
profile_tree="${output_dir}/profiles-${version}"
|
||||
log_path="${output_dir}/${version}.log"
|
||||
|
||||
curl -fsSL -o "${fixture_zip}" "${release_url}/${asset_url_name}"
|
||||
|
||||
if [ -n "${expected_sha256}" ] && [ "${expected_sha256}" != "<sha256>" ]; then
|
||||
echo "${expected_sha256} ${fixture_zip}" | sha256sum -c -
|
||||
fi
|
||||
|
||||
rm -rf "${profile_tree}"
|
||||
mkdir -p "${profile_tree}"
|
||||
cp -a "${{ github.workspace }}/resources/profiles/." "${profile_tree}/"
|
||||
rm -rf "${profile_tree}/user"
|
||||
unzip -q "${fixture_zip}" -d "${profile_tree}"
|
||||
|
||||
set +e
|
||||
./OrcaSlicer_profile_validator -p "${profile_tree}" -l 2 > "${log_path}" 2>&1
|
||||
result=$?
|
||||
set -e
|
||||
|
||||
if [ "${result}" -eq 0 ]; then
|
||||
echo "| ${version} | PASS | ${version}.log |" >> "${summary}"
|
||||
else
|
||||
echo "| ${version} | FAIL | ${version}.log |" >> "${summary}"
|
||||
failed_logs+=("${log_path}")
|
||||
status=1
|
||||
fi
|
||||
done < "${fixtures_dir}/fixtures.tsv"
|
||||
|
||||
{
|
||||
cat "${summary}"
|
||||
if [ "${#failed_logs[@]}" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "## Failed Fixture Logs"
|
||||
for log_path in "${failed_logs[@]}"; do
|
||||
echo ""
|
||||
echo "### $(basename "${log_path}" .log)"
|
||||
echo '```'
|
||||
head -c 12000 "${log_path}" || echo "No output captured"
|
||||
echo '```'
|
||||
done
|
||||
fi
|
||||
} | tee "${combined_log}"
|
||||
|
||||
exit "${status}"
|
||||
|
||||
- name: Prepare PR number for comment workflow
|
||||
if: ${{ always() && github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/profile-check-results
|
||||
echo "${{ github.event.pull_request.number }}" > ${{ runner.temp }}/profile-check-results/pr_number.txt
|
||||
|
||||
- name: Prepare comment artifact
|
||||
if: ${{ always() && github.event_name == 'pull_request' && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
{
|
||||
# Marker matched by check_profiles_comment.yml to delete prior comments.
|
||||
echo "<!-- profile-validation-comment -->"
|
||||
echo "## :x: Profile Validation Errors"
|
||||
echo ""
|
||||
|
||||
if [ "${{ steps.extra_json_check.outcome }}" = "failure" ]; then
|
||||
echo "### Extra JSON Check Failed"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/extra_json_check.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_system.outcome }}" = "failure" ]; then
|
||||
echo "### System Profile Validation Failed"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/validate_system.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_filament_subtypes.outcome }}" = "failure" ]; then
|
||||
echo "### BBL Filament Subtype Validation Failed"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/validate_filament_subtypes.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ "${{ steps.validate_custom.outcome }}" = "failure" ]; then
|
||||
echo "### Custom Preset Validation Failed"
|
||||
echo ""
|
||||
echo '```'
|
||||
head -c 30000 ${{ runner.temp }}/validate_custom.log || echo "No output captured"
|
||||
echo '```'
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
echo "*Please fix the above errors and push a new commit.*"
|
||||
} > ${{ runner.temp }}/profile-check-results/pr_comment.md
|
||||
|
||||
- name: Upload comment artifact
|
||||
if: ${{ always() && github.event_name == 'pull_request' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: profile-check-results
|
||||
path: ${{ runner.temp }}/profile-check-results/
|
||||
retention-days: 1
|
||||
|
||||
- name: Fail if any check failed
|
||||
if: ${{ always() && (steps.extra_json_check.outcome == 'failure' || steps.validate_system.outcome == 'failure' || steps.validate_filament_subtypes.outcome == 'failure' || steps.validate_custom.outcome == 'failure') }}
|
||||
run: |
|
||||
echo "One or more profile checks failed. See above for details."
|
||||
exit 1
|
||||
66
.github/workflows/check_profiles_comment.yml
vendored
@@ -1,66 +0,0 @@
|
||||
name: Post profile check comment
|
||||
|
||||
# NOTE: The workflow name in the 'workflows' filter below must match the 'name'
|
||||
# field in check_profiles.yml exactly. If that name changes, update it here too.
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Check profiles"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
# Needed to delete outdated bot comments via the issues/comments endpoint.
|
||||
issues: write
|
||||
|
||||
# Serialize handlers per source branch so parallel runs don't race delete-and-post.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
post_comment:
|
||||
name: Post PR comment
|
||||
runs-on: ubuntu-24.04
|
||||
if: ${{ github.event.workflow_run.event == 'pull_request' && (github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure') }}
|
||||
steps:
|
||||
- name: Download artifact
|
||||
id: download
|
||||
uses: actions/download-artifact@v8
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: profile-check-results
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ github.token }}
|
||||
|
||||
- name: Update PR comment
|
||||
if: ${{ steps.download.outcome == 'success' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
if [ ! -f pr_number.txt ]; then
|
||||
echo "No pr_number.txt in artifact, skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PR_NUMBER=$(cat pr_number.txt)
|
||||
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid PR number: $PR_NUMBER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Delete prior comments matching the marker (from check_profiles.yml) or the legacy heading.
|
||||
OLD_IDS=$(gh api --paginate "repos/${GH_REPO}/issues/${PR_NUMBER}/comments" \
|
||||
--jq '.[] | select(.user.login == "github-actions[bot]") | select((.body | startswith("<!-- profile-validation-comment -->")) or (.body | startswith("## :x: Profile Validation Errors"))) | .id')
|
||||
for comment_id in $OLD_IDS; do
|
||||
echo "Deleting outdated profile-validation comment ${comment_id}"
|
||||
gh api -X DELETE "repos/${GH_REPO}/issues/comments/${comment_id}" || true
|
||||
done
|
||||
|
||||
# Post a new comment only when validation failed (pr_comment.md present).
|
||||
if [ -f pr_comment.md ]; then
|
||||
gh pr comment "$PR_NUMBER" --body-file pr_comment.md
|
||||
else
|
||||
echo "Validation succeeded; cleaned up prior comments without posting."
|
||||
fi
|
||||
81
.github/workflows/dedupe-issues.yml
vendored
@@ -1,81 +0,0 @@
|
||||
name: Orca Issue Dedupe
|
||||
description: Automatically dedupe GitHub issues using AI
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: 'Issue number to process for duplicate detection'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
dedupe-issues:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Run Claude Code slash command
|
||||
uses: anthropics/claude-code-base-action@beta
|
||||
with:
|
||||
prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}"
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
claude_args: "--model claude-sonnet-4-5-20250929"
|
||||
claude_env: |
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log duplicate comment event to Statsig
|
||||
if: always()
|
||||
env:
|
||||
STATSIG_API_KEY: ${{ secrets.STATSIG_API_KEY }}
|
||||
run: |
|
||||
ISSUE_NUMBER=${{ github.event.issue.number || inputs.issue_number }}
|
||||
REPO=${{ github.repository }}
|
||||
|
||||
if [ -z "$STATSIG_API_KEY" ]; then
|
||||
echo "STATSIG_API_KEY not found, skipping Statsig logging"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Prepare the event payload
|
||||
EVENT_PAYLOAD=$(jq -n \
|
||||
--arg issue_number "$ISSUE_NUMBER" \
|
||||
--arg repo "$REPO" \
|
||||
--arg triggered_by "${{ github.event_name }}" \
|
||||
'{
|
||||
events: [{
|
||||
eventName: "github_duplicate_comment_added",
|
||||
value: 1,
|
||||
metadata: {
|
||||
repository: $repo,
|
||||
issue_number: ($issue_number | tonumber),
|
||||
triggered_by: $triggered_by,
|
||||
workflow_run_id: "${{ github.run_id }}"
|
||||
},
|
||||
time: (now | floor | tostring)
|
||||
}]
|
||||
}')
|
||||
|
||||
# Send to Statsig API
|
||||
echo "Logging duplicate comment event to Statsig for issue #${ISSUE_NUMBER}"
|
||||
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST https://events.statsigapi.net/v1/log_event \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "STATSIG-API-KEY: ${STATSIG_API_KEY}" \
|
||||
-d "$EVENT_PAYLOAD")
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
BODY=$(echo "$RESPONSE" | head -n-1)
|
||||
|
||||
if [ "$HTTP_CODE" -eq 200 ] || [ "$HTTP_CODE" -eq 202 ]; then
|
||||
echo "Successfully logged duplicate comment event for issue #${ISSUE_NUMBER}"
|
||||
else
|
||||
echo "Failed to log duplicate comment event for issue #${ISSUE_NUMBER}. HTTP ${HTTP_CODE}: ${BODY}"
|
||||
fi
|
||||
78
.github/workflows/doxygen-docs.yml
vendored
@@ -1,78 +0,0 @@
|
||||
name: Generate Doxygen Documentation
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 1' # Every Monday at midnight UTC
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Build and Deploy Docs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
# Only run on main branch of the main repository
|
||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main'
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: thejerrybao/setup-swap-space@v1
|
||||
with:
|
||||
swap-space-path: /swapfile
|
||||
swap-size-gb: 8
|
||||
remove-existing-swap-files: true
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Install Doxygen and Graphviz
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y doxygen graphviz
|
||||
|
||||
- name: Generate documentation
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Override DOT_NUM_THREADS to avoid parallel dot race condition bug
|
||||
sed -i 's/^DOT_NUM_THREADS.*/DOT_NUM_THREADS = 1/' .doxygen
|
||||
doxygen .doxygen
|
||||
# Verify documentation was generated
|
||||
if [ ! -f "internal_docs/index.html" ]; then
|
||||
echo "Error: Documentation generation failed - index.html not found"
|
||||
exit 1
|
||||
fi
|
||||
- name: Install Rclone
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sudo -v
|
||||
curl -fsSL https://rclone.org/install.sh | sudo bash
|
||||
|
||||
- name: optimize
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -f internal_docs/Nodes.xml internal_docs/Tokens.xml
|
||||
find internal_docs -name "*.map" -type f -delete || true
|
||||
find internal_docs -name "*.md5" -type f -delete || true
|
||||
|
||||
- name: upload
|
||||
# We configure rclone dynamically using environment variables
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Remove existing config if it exists to avoid conflicts
|
||||
rclone config delete cloudflare 2>/dev/null || true
|
||||
rclone config create cloudflare s3 \
|
||||
provider Cloudflare \
|
||||
access_key_id ${{ secrets.R2_ACCESS_KEY_ID }} \
|
||||
secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }} \
|
||||
endpoint ${{ secrets.R2_ENDPOINT }}
|
||||
|
||||
rclone sync internal_docs/ cloudflare:orcaslicer-internals \
|
||||
--progress \
|
||||
--transfers 512 \
|
||||
--checkers 512
|
||||
|
||||
echo "Documentation upload completed successfully"
|
||||
275
.github/workflows/pr-label-bot.yml
vendored
@@ -1,275 +0,0 @@
|
||||
name: PR Label Bot
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
issue_comment:
|
||||
types:
|
||||
- created
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
request-label:
|
||||
if: github.event_name == 'pull_request_target' && github.event.pull_request.author_association != 'COLLABORATOR' && github.event.pull_request.author_association != 'OWNER' && github.event.pull_request.author_association != 'MEMBER'
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Ask PR author for label
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
function isPermissionDenied(error) {
|
||||
return error && error.status === 403 && /Resource not accessible by integration/i.test(error.message || '');
|
||||
}
|
||||
|
||||
const allowedLabels = [
|
||||
'bug-fix',
|
||||
'enhancement',
|
||||
'Localization',
|
||||
'profile',
|
||||
'QoL',
|
||||
'UI/UX',
|
||||
'dependencies'
|
||||
];
|
||||
const pr = context.payload.pull_request;
|
||||
const labelsList = `${allowedLabels
|
||||
.slice(0, -1)
|
||||
.map((label) => `\`${label}\``)
|
||||
.join(', ')} and \`${allowedLabels[allowedLabels.length - 1]}\`.`;
|
||||
const examplesText = [
|
||||
'```',
|
||||
'/bot add-label bug-fix',
|
||||
'```',
|
||||
'```',
|
||||
'/bot add-label bug-fix, UI/UX',
|
||||
'```',
|
||||
'```',
|
||||
'/bot remove-label bug-fix, UI/UX',
|
||||
'```'
|
||||
].join('\n');
|
||||
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body:
|
||||
`Hi @${pr.user.login}, you can manage the labels for this PR by \`/bot add-label\` and \`/bot remove-label\`\n\n` +
|
||||
`Allowed labels are:\n${labelsList}\n\n` +
|
||||
`Examples:\n${examplesText}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Skipping PR comment because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
apply-label:
|
||||
if: github.event_name == 'issue_comment'
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply label command from PR author
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
function isPermissionDenied(error) {
|
||||
return error && error.status === 403 && /Resource not accessible by integration/i.test(error.message || '');
|
||||
}
|
||||
|
||||
const allowedLabels = [
|
||||
'bug-fix',
|
||||
'enhancement',
|
||||
'Localization',
|
||||
'profile',
|
||||
'QoL',
|
||||
'UI/UX',
|
||||
'dependencies'
|
||||
];
|
||||
|
||||
const issue = context.payload.issue;
|
||||
if (!issue.pull_request) {
|
||||
core.info('Ignoring comment that is not on a pull request.');
|
||||
return;
|
||||
}
|
||||
|
||||
const body = (context.payload.comment.body || '').trim();
|
||||
const commandLine = body
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.find((line) => /^\/bot\s+(add-label|remove-label)(?:\s*:\s*|\s+)/i.test(line));
|
||||
|
||||
if (!commandLine) {
|
||||
core.info('No /bot add-label or /bot remove-label command found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const commandMatch = commandLine.match(/^\/bot\s+(add-label|remove-label)(?:\s*:\s*|\s+)(.+)\s*$/i);
|
||||
if (!commandMatch) {
|
||||
core.info('Label command format is invalid.');
|
||||
return;
|
||||
}
|
||||
|
||||
const action = commandMatch[1].toLowerCase() === 'add-label' ? 'add' : 'remove';
|
||||
let labelsExpr = (commandMatch[2] || '').trim();
|
||||
if (!labelsExpr) {
|
||||
core.info('Label command is missing label name.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (labelsExpr.startsWith('[') && labelsExpr.endsWith(']')) {
|
||||
labelsExpr = labelsExpr.slice(1, -1).trim();
|
||||
}
|
||||
|
||||
const requestedRawLabels = labelsExpr
|
||||
.split(',')
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
if (!requestedRawLabels.length) {
|
||||
core.info('No labels were provided in the command.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: issue.number
|
||||
});
|
||||
|
||||
const commenter = context.payload.comment.user.login;
|
||||
if (commenter !== pr.user.login) {
|
||||
core.info('Ignoring command because commenter is not the PR author.');
|
||||
return;
|
||||
}
|
||||
|
||||
const labelsByLower = new Map(
|
||||
allowedLabels.map((label) => [label.toLowerCase(), label])
|
||||
);
|
||||
|
||||
const resolvedLabels = [];
|
||||
const invalidLabels = [];
|
||||
|
||||
for (const rawLabel of requestedRawLabels) {
|
||||
const resolved = labelsByLower.get(rawLabel.toLowerCase());
|
||||
if (resolved) {
|
||||
resolvedLabels.push(resolved);
|
||||
} else {
|
||||
invalidLabels.push(rawLabel);
|
||||
}
|
||||
}
|
||||
const uniqueRequestedLabels = [...new Set(resolvedLabels)];
|
||||
|
||||
if (action === 'add' && uniqueRequestedLabels.length) {
|
||||
try {
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
labels: uniqueRequestedLabels
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Cannot add labels because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
core.info(`Added labels: ${uniqueRequestedLabels.join(', ')}`);
|
||||
}
|
||||
|
||||
if (action === 'remove' && uniqueRequestedLabels.length) {
|
||||
let removedCount = 0;
|
||||
try {
|
||||
for (const label of uniqueRequestedLabels) {
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
name: label
|
||||
});
|
||||
removedCount += 1;
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning(
|
||||
'Cannot remove labels because token cannot write. Enable Actions write permissions, ' +
|
||||
'or run with a token that has issues:write and pull_requests:write.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error.status === 404) {
|
||||
core.info(`Label is not currently applied: ${label}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
core.info(`Removed labels count: ${removedCount}`);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uniqueRequestedLabels.length) {
|
||||
core.info('No valid labels were provided in the command.');
|
||||
}
|
||||
|
||||
if (invalidLabels.length) {
|
||||
const allowedText = allowedLabels.map((label) => `\`${label}\``).join(', ');
|
||||
const invalidText = invalidLabels.map((label) => `\`${label}\``).join(', ');
|
||||
const validText = uniqueRequestedLabels.length
|
||||
? `\n\nProcessed valid label(s): ${uniqueRequestedLabels.map((label) => `\`${label}\``).join(', ')}`
|
||||
: '';
|
||||
|
||||
try {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body:
|
||||
`@${commenter} invalid label(s): ${invalidText}.${validText}\n\n` +
|
||||
`Allowed labels: ${allowedText}\n\n` +
|
||||
`Use:\n` +
|
||||
`- \`/bot add-label label\`\n` +
|
||||
`- \`/bot remove-label label\`\n` +
|
||||
`- \`/bot add-label label1, label2\``
|
||||
});
|
||||
} catch (error) {
|
||||
if (isPermissionDenied(error)) {
|
||||
core.warning('Cannot post invalid-label feedback because token cannot write comments.');
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
const processedLabelsText = uniqueRequestedLabels.length ? uniqueRequestedLabels.join(', ') : '(none)';
|
||||
core.info(`Processed label command: ${action} ${processedLabelsText}`);
|
||||
131
.github/workflows/publish_release.yml
vendored
@@ -1,131 +0,0 @@
|
||||
name: Publish to draft release
|
||||
|
||||
# Manually pulls the platform binaries produced by a "Build all" run and uploads
|
||||
# them to an existing DRAFT release. Decoupled from the build so you can test a
|
||||
# build first, then publish exactly that run's artifacts once you're happy.
|
||||
#
|
||||
# Trigger: Actions tab -> "Publish to draft release" -> Run workflow.
|
||||
# Locked to a single person: the first step aborts unless the actor matches the
|
||||
# `RELEASE_PUBLISHER` repo variable (set to "SoftFever"). To allow someone else,
|
||||
# change that variable: gh variable set RELEASE_PUBLISHER --body "<login>".
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_id:
|
||||
description: 'Run ID of the "Build all" workflow to pull binaries from (the number in the Actions run URL)'
|
||||
required: true
|
||||
type: string
|
||||
tag:
|
||||
description: 'Tag of the draft release to upload to (e.g. v2.4.0-beta)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write # upload release assets
|
||||
actions: read # download artifacts from another run
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish binaries to draft release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RUN_ID: ${{ inputs.run_id }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
steps:
|
||||
- name: Restrict to the release publisher
|
||||
env:
|
||||
PUBLISHER: ${{ vars.RELEASE_PUBLISHER }}
|
||||
run: |
|
||||
if [ -z "$PUBLISHER" ]; then
|
||||
echo "::error::RELEASE_PUBLISHER repo variable is not set."
|
||||
exit 1
|
||||
fi
|
||||
if [ "${{ github.actor }}" != "$PUBLISHER" ]; then
|
||||
echo "::error::Only @$PUBLISHER may run this workflow (you are @${{ github.actor }})."
|
||||
exit 1
|
||||
fi
|
||||
echo "Authorized: @${{ github.actor }}"
|
||||
|
||||
- name: Verify target is a draft release
|
||||
run: |
|
||||
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isDraft >/dev/null 2>&1; then
|
||||
echo "::error::Release '$TAG' not found. Create the draft (with this tag) first."
|
||||
exit 1
|
||||
fi
|
||||
is_draft=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isDraft --jq '.isDraft')
|
||||
if [ "$is_draft" != "true" ]; then
|
||||
echo "::error::Release '$TAG' is published, not a draft. Aborting to avoid touching a live release."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verify source build run
|
||||
run: |
|
||||
info=$(gh run view "$RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,conclusion,headBranch)
|
||||
name=$(echo "$info" | jq -r '.workflowName')
|
||||
conclusion=$(echo "$info" | jq -r '.conclusion')
|
||||
branch=$(echo "$info" | jq -r '.headBranch')
|
||||
echo "Source run #$RUN_ID: '$name' on '$branch' (conclusion: $conclusion)"
|
||||
if [ "$conclusion" != "success" ]; then
|
||||
echo "::warning::Source run did not conclude 'success' ($conclusion). Some assets may be missing."
|
||||
fi
|
||||
|
||||
- name: Download release artifacts from build run
|
||||
run: |
|
||||
# Windows_V* (not Windows_*) keeps the MSIX Store artifact out: it goes to Partner Center, not GitHub releases.
|
||||
gh run download "$RUN_ID" --repo "$GITHUB_REPOSITORY" --dir artifacts \
|
||||
-p 'OrcaSlicer_Windows_V*' \
|
||||
-p 'OrcaSlicer_Mac_universal_*' \
|
||||
-p 'OrcaSlicer_Linux_ubuntu_*' \
|
||||
-p 'OrcaSlicer-Linux-flatpak_*' \
|
||||
-p 'PDB'
|
||||
echo "Downloaded artifact folders:"
|
||||
ls -1 artifacts
|
||||
|
||||
- name: Assemble release assets
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p upload
|
||||
|
||||
# gh run download auto-extracts each artifact into a folder, so the inner
|
||||
# binaries are already unzipped. Copy the inner binary for each platform.
|
||||
# -type f is required (some artifact *folders* are named "*.flatpak").
|
||||
|
||||
# Windows installers (x64 + arm64): the .exe inside each installer
|
||||
# artifact, NOT the orca-slicer.exe in the portable app folder. CPack
|
||||
# now bakes the arch into the filename (…_x64.exe / …_arm64.exe), so
|
||||
# copy them straight through.
|
||||
find artifacts -type f -name '*.exe' -path '*OrcaSlicer_Windows_V*' ! -path '*_portable*' -exec cp -v {} upload/ \;
|
||||
# macOS universal DMG (profile-validator DMG isn't downloaded).
|
||||
find artifacts -type f -name '*.dmg' -path '*OrcaSlicer_Mac_universal_*' -exec cp -v {} upload/ \;
|
||||
# Linux AppImage.
|
||||
find artifacts -type f -name '*.AppImage' -exec cp -v {} upload/ \;
|
||||
# Flatpak bundles (x86_64 + aarch64).
|
||||
find artifacts -type f -name '*.flatpak' -exec cp -v {} upload/ \;
|
||||
# Windows debug symbols (PDB archive, for developers).
|
||||
find artifacts -type f -name 'Debug_PDB_*.7z' -exec cp -v {} upload/ \;
|
||||
|
||||
# Portable Windows builds (x64 + arm64) are unzipped folder artifacts;
|
||||
# re-zip each to its released filename (these stay .zip on the release).
|
||||
mapfile -t portable_dirs < <(find artifacts -maxdepth 1 -type d -name 'OrcaSlicer_Windows_*_portable')
|
||||
if [ ${#portable_dirs[@]} -eq 0 ]; then
|
||||
echo "::warning::Windows portable artifact not found."
|
||||
fi
|
||||
for portable_dir in "${portable_dirs[@]}"; do
|
||||
( cd "$portable_dir" && zip -qr "$GITHUB_WORKSPACE/upload/$(basename "$portable_dir").zip" . )
|
||||
echo "Zipped portable -> $(basename "$portable_dir").zip"
|
||||
done
|
||||
|
||||
echo "Assets to upload:"
|
||||
ls -lh upload
|
||||
if [ -z "$(ls -A upload)" ]; then
|
||||
echo "::error::No assets assembled. Check the run_id and that its artifacts haven't expired."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload assets to draft release
|
||||
run: |
|
||||
gh release upload "$TAG" upload/* --repo "$GITHUB_REPOSITORY" --clobber
|
||||
echo "Uploaded to draft release: $TAG"
|
||||
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name'
|
||||
44
.github/workflows/shellcheck.yml
vendored
@@ -1,44 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**.sh'
|
||||
- 'scripts/linux.d/*'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.sh'
|
||||
- 'scripts/linux.d/*'
|
||||
schedule:
|
||||
- cron: '55 7 * * *' # run once a day near midnight US Pacific time
|
||||
workflow_dispatch: # allows for manual dispatch
|
||||
|
||||
name: "Shellcheck"
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
shellcheck:
|
||||
name: Shellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cache shellcheck download
|
||||
id: cache-shellcheck-v0_11
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/shellcheck
|
||||
key: ${{ runner.os }}-shellcheck-v0_11
|
||||
|
||||
- name: Download shellcheck
|
||||
if: steps.cache-shellcheck-v0_11.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_VERSION: "v0.11.0"
|
||||
run: |
|
||||
curl -L#o ~/sc.tar.xz "https://github.com/koalaman/shellcheck/releases/download/${INPUT_VERSION}/shellcheck-${INPUT_VERSION}.linux.x86_64.tar.xz"
|
||||
tar -xvf ~/sc.tar.xz -C ~
|
||||
mv ~/shellcheck-"${INPUT_VERSION}"/shellcheck ~/shellcheck
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Shellcheck scripts
|
||||
run: 'find . -not -name \*.md \( -path ./scripts/linux.d/\* -o -name \*.sh \) -print0 | xargs -0 ~/shellcheck'
|
||||
38
.github/workflows/update-translation.yml
vendored
@@ -1,38 +0,0 @@
|
||||
name: Update Translation Catalog
|
||||
on:
|
||||
# schedule:
|
||||
# - cron: 0 0 * * 1
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update_translation:
|
||||
name: Update translation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install gettext
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gettext
|
||||
|
||||
- name: Update translation catalog
|
||||
run: |
|
||||
./scripts/run_gettext.sh --full
|
||||
git add localization/i18n/*
|
||||
|
||||
- name: Commit translation catalog updates
|
||||
uses: qoomon/actions--create-commit@v1
|
||||
id: commit
|
||||
with:
|
||||
message: Update translation catalog
|
||||
skip-empty: true
|
||||
|
||||
- name: Push changes
|
||||
run: git push
|
||||
14
.github/workflows/winget_updater.yml
vendored
@@ -1,14 +0,0 @@
|
||||
name: Publish to WinGet
|
||||
on:
|
||||
release:
|
||||
types: [ released ]
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: vedantmgoyal9/winget-releaser@main
|
||||
with:
|
||||
identifier: SoftFever.OrcaSlicer
|
||||
version: ${{ github.event.release.tag_name }}
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
installers-regex: '\.exe$'
|
||||
36
.gitignore
vendored
@@ -1,9 +1,7 @@
|
||||
Build
|
||||
Build.bat
|
||||
/build*/
|
||||
CMakeLists.txt.user
|
||||
**/CMakeLists.txt.autosave
|
||||
deps/build*
|
||||
/build/
|
||||
deps/build
|
||||
MYMETA.json
|
||||
MYMETA.yml
|
||||
_build
|
||||
@@ -19,33 +17,9 @@ xs/assertlib*
|
||||
local-lib
|
||||
/src/TAGS
|
||||
/.vscode/
|
||||
/.vscode
|
||||
build-linux/*
|
||||
deps/build*/*
|
||||
deps/build-linux/*
|
||||
**/.DS_Store
|
||||
install_*
|
||||
build_*/
|
||||
install_dir
|
||||
install_release
|
||||
SVG
|
||||
src/OrcaSlicer-doc/
|
||||
.idea/
|
||||
/.cache/
|
||||
*.mo
|
||||
**/process_full/
|
||||
**/machine_full/
|
||||
**/filament_full/
|
||||
/deps/DL_CACHE/
|
||||
/deps/DL_CACHE
|
||||
**/.flatpak-builder/
|
||||
*.no-debug.yml
|
||||
resources/profiles/user/default
|
||||
*.code-workspace
|
||||
deps_src/build/
|
||||
test.js
|
||||
/.cache/
|
||||
.clangd
|
||||
internal_docs/
|
||||
*.flatpak
|
||||
/flatpak-repo/
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
57
AGENTS.md
@@ -1,57 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
OrcaSlicer — open-source C++17 3D slicer. wxWidgets GUI, CMake build system.
|
||||
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
cmake --build build/arm64 --config RelWithDebInfo --target all --
|
||||
|
||||
# Linux
|
||||
cmake --build build --config RelWithDebInfo --target all --
|
||||
|
||||
# Windows (replace %build_type% with Debug/Release/RelWithDebInfo)
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Catch2 framework. Tests in `tests/` directory.
|
||||
|
||||
```bash
|
||||
cd build && ctest --output-on-failure # all tests
|
||||
ctest --test-dir ./tests/libslic3r # individual suite
|
||||
ctest --test-dir ./tests/fff_print
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
- C++17, selective C++20. PascalCase classes, snake_case functions/variables
|
||||
- `#pragma once` for headers. Smart pointers and RAII preferred
|
||||
- Parallelization via TBB — be mindful of shared state
|
||||
|
||||
## Key Entry Points
|
||||
|
||||
- App startup: `src/OrcaSlicer.cpp`
|
||||
- Slicing pipeline: `src/libslic3r/Print.cpp`
|
||||
- All print/printer/material settings: `src/libslic3r/PrintConfig.cpp`
|
||||
- GUI: `src/slic3r/GUI/`
|
||||
- Core algorithms: `src/libslic3r/` (GCode/, Fill/, Support/, Geometry/, Format/, Arachne/)
|
||||
- Printer profiles: `resources/profiles/[manufacturer].json`
|
||||
|
||||
## Critical Constraints
|
||||
|
||||
- **Backward compatibility required** for .3mf project files and printer profiles
|
||||
- **Cross-platform** — all changes must work on Windows, macOS, and Linux
|
||||
- Profile/format changes need version migration handling
|
||||
- Dependencies built separately in `deps/build/`, then linked to main app
|
||||
|
||||
## Code review focus areas
|
||||
|
||||
- Changes must not cause regressions in existing functionality, defaults, profiles, or project compatibility.
|
||||
- Features gated by options must not affect existing behavior when those options are disabled.
|
||||
- Changes should follow the existing code style and architecture. Architectural changes should be justified in code comments and the PR description.
|
||||
- Add helper functions or utilities only when existing code cannot reasonably be reused. Avoid duplication.
|
||||
- Keep code concise and clear. Manually simplify AI generated bloated codes before review.
|
||||
- Include targeted tests or documented verification for behavior changes, especially in slicing logic, profiles, formats, and GUI defaults.
|
||||
BIN
BambuStudio.mo
Normal file
103
BambuStudio.sublime-project
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name": "List",
|
||||
//"file_regex": " at ([^-\\s]*) line ([0-9]*)",
|
||||
// "file_regex": " at (D\\:\\/src\\/Slic3r\\/.*?) line ([0-9]*)",
|
||||
"shell_cmd": "ls -l"
|
||||
},
|
||||
{
|
||||
"name": "Run",
|
||||
"working_dir": "$project_path",
|
||||
"file_regex": " at (.*?) line ([0-9]*)",
|
||||
// "shell_cmd": "chdir & perl slic3r.pl --DataDir \"C:\\Users\\Public\\Documents\\Prusa3D\\Slic3r settings MK2\" --gui \"..\\Slic3r-tests\\gap fill torture 20 -rt.stl\""
|
||||
"shell_cmd": "chdir & perl slic3r.pl"
|
||||
},
|
||||
{
|
||||
"name": "full",
|
||||
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & perl Build.pl"
|
||||
},
|
||||
{
|
||||
"name": "xs",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$",
|
||||
// For GCC:
|
||||
// "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & ninja -j 6 -v",
|
||||
"env": {
|
||||
// "PATH": "C:\\Program Files (x86)\\MSBuild\\12.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools;%PATH%;c:\\wperl64d\\site\\bin;c:\\wperl64d\\bin",
|
||||
// "PERL_CPANM_HOME": "c:\\wperl64d\\cpanm",
|
||||
// "WXDIR": "D:\\src-perl\\wxWidgets-3.0.3-beta1",
|
||||
// "BOOST_DIR": "D:\\src-perl\\boost_1_61_0",
|
||||
// "BOOST_INCLUDEDIR": "D:\\src-perl\\boost_1_61_0",
|
||||
// "BOOST_LIBRARYDIR": "D:\\src-perl\\boost_1_61_0\\stage\\x64\\lib",
|
||||
// "SLIC3R_STATIC": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "xs & run",
|
||||
"working_dir": "$project_path/build",
|
||||
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
|
||||
"shell_cmd": "chdir & ninja -j 6 & cd .. & perl slic3r.pl --gui \"..\\Slic3r-tests\\star3-big2.stl\""
|
||||
},
|
||||
{
|
||||
"name": "Slic3r - clean",
|
||||
"working_dir": "$project_path/build",
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": ["chdir & ninja clean"]
|
||||
},
|
||||
{
|
||||
"name": "run tests",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$",
|
||||
"shell_cmd": "chdir & ctest --verbose"
|
||||
},
|
||||
{
|
||||
"name": "Clean & Configure",
|
||||
"working_dir": "$project_path",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": "chdir & rmdir /S /Q build & mkdir build & cd build & cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "Configure",
|
||||
"working_dir": "$project_path/build",
|
||||
// for Visual Studio:
|
||||
"file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)",
|
||||
"shell_cmd": "cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
}
|
||||
],
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": ".",
|
||||
// "folder_exclude_patterns": [".svn", "._d", ".metadata", ".settings"],
|
||||
"file_exclude_patterns": ["XS.c", "*.pch", "*.ilk", "*.js" ]
|
||||
}
|
||||
],
|
||||
|
||||
"settings":
|
||||
{
|
||||
"sublimegdb_workingdir": "${folder:${project_path:run}}",
|
||||
// NOTE: You MUST provide --interpreter=mi for the plugin to work
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -ex 'target localhost:2345'",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args perl slic3r.pl",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args slic3r.pl ",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -e C:\\Strawberry\\perl\\bin\\perl.exe -s C:\\Strawberry\\perl\\site\\lib\\auto\\Slic3r\\XS\\XS.xs.dll --args perl slic3r.pl -j 1 --gui D:\\src\\Slic3r-tests\\star3-big.stl",
|
||||
"sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl.exe --args perl slic3r.pl -j 1 --gui", // D:\\src\\Slic3r-tests\\star3-big.stl",
|
||||
// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -x slic3r.gdb",
|
||||
// "arguments": "slic3r -j 1 --gui ../Slic3r-tests/star3-big.stl",
|
||||
// "arguments": "../slic3r.pl -j 1 --gui",
|
||||
// "sublimegdb_exec_cmd": "-exec-continue",
|
||||
|
||||
// Add "pending breakpoints" for symbols that are dynamically loaded from
|
||||
// external shared libraries
|
||||
"debug_ext" : true,
|
||||
"run_after_init": false,
|
||||
"close_views": false
|
||||
}
|
||||
}
|
||||
132
Build.PL
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
print "This script is currently used for installing Perl dependenices for running\n";
|
||||
print "the libslic3r unit / integration tests through Perl prove.\n";
|
||||
print "If you don't plan to run the unit / integration tests, you don't need to\n";
|
||||
print "install these dependencies to build and run BambuSlicer.\n";
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Config;
|
||||
use File::Spec;
|
||||
|
||||
my %prereqs = qw(
|
||||
Devel::CheckLib 0
|
||||
ExtUtils::MakeMaker 6.80
|
||||
ExtUtils::ParseXS 3.22
|
||||
ExtUtils::XSpp 0
|
||||
ExtUtils::XSpp::Cmd 0
|
||||
ExtUtils::CppGuess 0
|
||||
ExtUtils::Typemaps 0
|
||||
ExtUtils::Typemaps::Basic 0
|
||||
File::Basename 0
|
||||
File::Spec 0
|
||||
Getopt::Long 0
|
||||
Module::Build::WithXSpp 0.14
|
||||
Moo 1.003001
|
||||
POSIX 0
|
||||
Scalar::Util 0
|
||||
Test::More 0
|
||||
IO::Scalar 0
|
||||
Time::HiRes 0
|
||||
);
|
||||
my %recommends = qw(
|
||||
Class::XSAccessor 0
|
||||
Test::Harness 0
|
||||
);
|
||||
|
||||
my $sudo = grep { $_ eq '--sudo' } @ARGV;
|
||||
my $nolocal = grep { $_ eq '--nolocal' } @ARGV;
|
||||
|
||||
my @missing_prereqs = ();
|
||||
if ($ENV{SLIC3R_NO_AUTO}) {
|
||||
foreach my $module (sort keys %prereqs) {
|
||||
my $version = $prereqs{$module};
|
||||
next if eval "use $module $version; 1";
|
||||
push @missing_prereqs, $module if exists $prereqs{$module};
|
||||
print "Missing prerequisite $module $version\n";
|
||||
}
|
||||
foreach my $module (sort keys %recommends) {
|
||||
my $version = $recommends{$module};
|
||||
next if eval "use $module $version; 1";
|
||||
print "Missing optional $module $version\n";
|
||||
}
|
||||
} else {
|
||||
my @try = (
|
||||
$ENV{CPANM} // (),
|
||||
File::Spec->catfile($Config{sitebin}, 'cpanm'),
|
||||
File::Spec->catfile($Config{installscript}, 'cpanm'),
|
||||
);
|
||||
|
||||
my $cpanm;
|
||||
foreach my $path (@try) {
|
||||
if (-e $path) { # don't use -x because it fails on Windows
|
||||
$cpanm = $path;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if (!$cpanm) {
|
||||
if ($^O =~ /^(?:darwin|linux)$/ && system(qw(which cpanm)) == 0) {
|
||||
$cpanm = 'cpanm';
|
||||
}
|
||||
}
|
||||
die <<'EOF'
|
||||
cpanm was not found. Please install it before running this script.
|
||||
|
||||
There are several ways to install cpanm, try one of these:
|
||||
|
||||
apt-get install cpanminus
|
||||
curl -L http://cpanmin.us | perl - --sudo App::cpanminus
|
||||
cpan App::cpanminus
|
||||
|
||||
If it is installed in a non-standard location you can do:
|
||||
|
||||
CPANM=/path/to/cpanm perl Build.PL
|
||||
|
||||
EOF
|
||||
if !$cpanm;
|
||||
my @cpanm_args = ();
|
||||
push @cpanm_args, "--sudo" if $sudo;
|
||||
|
||||
# install local::lib without --local-lib otherwise it's not usable afterwards
|
||||
if (!eval "use local::lib qw(local-lib); 1") {
|
||||
my $res = system $cpanm, @cpanm_args, 'local::lib';
|
||||
warn "Warning: local::lib is required. You might need to run the `cpanm --sudo local::lib` command in order to install it.\n"
|
||||
if $res != 0;
|
||||
}
|
||||
|
||||
push @cpanm_args, ('--local-lib', 'local-lib') if ! $nolocal;
|
||||
|
||||
# make sure our cpanm is updated (old ones don't support the ~ syntax)
|
||||
system $cpanm, @cpanm_args, 'App::cpanminus';
|
||||
|
||||
my %modules = (%prereqs, %recommends);
|
||||
foreach my $module (sort keys %modules) {
|
||||
my $version = $modules{$module};
|
||||
my @cmd = ($cpanm, @cpanm_args);
|
||||
|
||||
# temporary workaround for upstream bug in test
|
||||
push @cmd, '--notest'
|
||||
if $module =~ /^(?:OpenGL|Test::Harness)$/;
|
||||
|
||||
push @cmd, "$module~$version";
|
||||
|
||||
my $res = system @cmd;
|
||||
if ($res != 0) {
|
||||
if (exists $prereqs{$module}) {
|
||||
push @missing_prereqs, $module;
|
||||
} else {
|
||||
printf "Don't worry, this module is optional.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print "In the next step, you need to build the BambuStudio C++ library.\n";
|
||||
print "1) Create a build directory and change to it\n";
|
||||
print "2) run cmake .. -DCMAKE_BUILD_TYPE=Release\n";
|
||||
print "3) run make\n";
|
||||
print "4) to execute the automatic tests, run ctest --verbose\n";
|
||||
__END__
|
||||
624
CMakeLists.txt
@@ -1,70 +1,5 @@
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "4.0")
|
||||
set(CMAKE_POLICY_VERSION_MINIMUM 3.13 CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
|
||||
# The following line used to be in tests/CMakeLists.txt
|
||||
# Having it there causes rebuilds of all targets on any CMakeLists.txt change under tests/
|
||||
# It has no effect on how code is compiled or linked.
|
||||
# It just lets you later do `set_property(TARGET foo PROPERTY FOLDER "bar")`
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if (WIN32)
|
||||
# Detect known CI environments
|
||||
set(IS_CI FALSE)
|
||||
if(DEFINED ENV{CI})
|
||||
set(IS_CI TRUE)
|
||||
elseif(DEFINED ENV{GITHUB_ACTIONS})
|
||||
set(IS_CI TRUE)
|
||||
elseif(DEFINED ENV{GITLAB_CI})
|
||||
set(IS_CI TRUE)
|
||||
elseif(DEFINED ENV{TF_BUILD})
|
||||
set(IS_CI TRUE)
|
||||
elseif(DEFINED ENV{BUILD_NUMBER}) # Jenkins
|
||||
set(IS_CI TRUE)
|
||||
endif()
|
||||
|
||||
# Detect common misconfiguration (Strawberry Perl in PATH before CMake)
|
||||
# We use ENV to check the PATH order
|
||||
string(REPLACE "\\" "/" ENV_PATH "$ENV{PATH}")
|
||||
string(FIND "${ENV_PATH}" "Strawberry/c/bin" STRAWBERRY_POS)
|
||||
string(FIND "${ENV_PATH}" "Program Files/CMake/bin" CMAKE_POS)
|
||||
|
||||
if (STRAWBERRY_POS GREATER -1 AND CMAKE_POS GREATER -1 AND STRAWBERRY_POS LESS CMAKE_POS)
|
||||
set(_warning_text "
|
||||
#############################################################
|
||||
Detected Strawberry Perl's 'c/bin' appearing before CMake in PATH.
|
||||
This is known to cause CMake to misbehave (e.g., missing modules).
|
||||
Please adjust your PATH so that:
|
||||
C:\\Program Files\\CMake\\bin
|
||||
appears before:
|
||||
C:\\Strawberry\\c\\bin
|
||||
You can do this in Environment Variables settings.
|
||||
#############################################################
|
||||
")
|
||||
|
||||
if(NOT IS_CI)
|
||||
message(FATAL_ERROR "${_warning_text}")
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
# if CMAKE_OSX_DEPLOYMENT_TARGET is not set, set it to 11.3
|
||||
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.3" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||
endif ()
|
||||
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif ()
|
||||
|
||||
project(OrcaSlicer)
|
||||
|
||||
# Backward compatibility for old CMake versions
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_VERSION VERSION_LESS "3.25")
|
||||
set(LINUX ON CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
project(BambuStudio)
|
||||
|
||||
include("version.inc")
|
||||
include(GNUInstallDirs)
|
||||
@@ -78,76 +13,37 @@ if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (default Release)" FORCE)
|
||||
endif()
|
||||
|
||||
if (DEFINED BBL_RELEASE_TO_PUBLIC)
|
||||
add_compile_definitions("BBL_RELEASE_TO_PUBLIC=${BBL_RELEASE_TO_PUBLIC}")
|
||||
else ()
|
||||
add_compile_definitions("BBL_RELEASE_TO_PUBLIC=$<CONFIG:Release>")
|
||||
endif ()
|
||||
|
||||
find_package(Git)
|
||||
if(DEFINED ENV{git_commit_hash} AND NOT "$ENV{git_commit_hash}" STREQUAL "")
|
||||
message(STATUS "Specified git commit hash: $ENV{git_commit_hash}")
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
# Convert the given hash to short hash
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short "$ENV{git_commit_hash}"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else()
|
||||
# No .git directory (e.g., Flatpak sandbox) — truncate directly
|
||||
string(SUBSTRING "$ENV{git_commit_hash}" 0 7 GIT_COMMIT_HASH)
|
||||
endif()
|
||||
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
||||
elseif(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
# Check current Git commit hash
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} log -1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{SLIC3R_STATIC})
|
||||
set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC})
|
||||
set(SLIC3R_STATIC_INITIAL $ENV{SLIC3R_STATIC})
|
||||
else()
|
||||
set(SLIC3R_STATIC_INITIAL 1)
|
||||
if (MSVC OR MINGW OR APPLE)
|
||||
set(SLIC3R_STATIC_INITIAL 1)
|
||||
else()
|
||||
set(SLIC3R_STATIC_INITIAL 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SLIC3R_STATIC "Compile OrcaSlicer with static libraries (Boost, TBB)" ${SLIC3R_STATIC_INITIAL})
|
||||
option(SLIC3R_GUI "Compile OrcaSlicer with GUI components (OpenGL, wxWidgets)" 1)
|
||||
option(SLIC3R_FHS "Assume OrcaSlicer is to be installed in a FHS directory structure" 0)
|
||||
option(SLIC3R_PROFILE "Compile OrcaSlicer with an invasive Shiny profiler" 0)
|
||||
option(SLIC3R_STATIC "Compile BambuStudio with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL})
|
||||
option(SLIC3R_GUI "Compile BambuStudio with GUI components (OpenGL, wxWidgets)" 1)
|
||||
option(SLIC3R_FHS "Assume BambuStudio is to be installed in a FHS directory structure" 0)
|
||||
option(SLIC3R_WX_STABLE "Build against wxWidgets stable (3.0) as oppsed to dev (3.1) on Linux" 0)
|
||||
option(SLIC3R_PROFILE "Compile BambuStudio with an invasive Shiny profiler" 0)
|
||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||
# If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable.
|
||||
CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow performing desktop integration during runtime" 1 "NOT SLIC3R_FHS" 0)
|
||||
CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 1 "NOT SLIC3R_FHS" 0)
|
||||
|
||||
set(OPENVDB_FIND_MODULE_PATH "" CACHE PATH "Path to OpenVDB installation's find modules.")
|
||||
|
||||
set(SLIC3R_GTK "3" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
||||
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
||||
|
||||
set(IS_CROSS_COMPILE FALSE)
|
||||
|
||||
option (COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF)
|
||||
if (${COLORED_OUTPUT})
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_compile_options (-fdiagnostics-color=always)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options (-fcolor-diagnostics)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES _arch_len)
|
||||
if (_arch_len GREATER 1)
|
||||
message(FATAL_ERROR "OrcaSlicer only supports building for one architecture at a time. Please make sure only one architecture is specified in CMAKE_OSX_ARCHITECTURES")
|
||||
endif ()
|
||||
set(CMAKE_FIND_FRAMEWORK LAST)
|
||||
set(CMAKE_FIND_APPBUNDLE LAST)
|
||||
list(FIND CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR} _arch_idx)
|
||||
@@ -157,24 +53,16 @@ if (APPLE)
|
||||
if (CMAKE_MACOSX_BUNDLE)
|
||||
set(CMAKE_INSTALL_RPATH @executable_path/../Frameworks)
|
||||
endif()
|
||||
SET(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.orcaslicer.OrcaSlicer")
|
||||
|
||||
message(STATUS "Orca: IS_CROSS_COMPILE: ${IS_CROSS_COMPILE}")
|
||||
endif ()
|
||||
|
||||
# Proposal for C++ unit tests and sandboxes
|
||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||
option(BUILD_TESTS "Build unit tests" OFF)
|
||||
option(ORCA_TOOLS "Build Orca tools" OFF)
|
||||
|
||||
if (FLATPAK)
|
||||
set(SLIC3R_FHS ON CACHE BOOL "" FORCE)
|
||||
set(SLIC3R_DESKTOP_INTEGRATION OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
option(SLIC3R_BUILD_TESTS "Build unit tests" OFF)
|
||||
|
||||
if (IS_CROSS_COMPILE)
|
||||
message("Detected cross compilation setup. Tests and encoding checks will be forcedly disabled!")
|
||||
set(BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
set(SLIC3R_PERL_XS OFF CACHE BOOL "" FORCE)
|
||||
set(SLIC3R_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
# Print out the SLIC3R_* cache options
|
||||
@@ -194,13 +82,6 @@ if(SLIC3R_DESKTOP_INTEGRATION)
|
||||
add_definitions(-DSLIC3R_DESKTOP_INTEGRATION)
|
||||
endif ()
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
message(STATUS "Automatically setting CMAKE_INSTALL_PREFIX")
|
||||
set_property(CACHE CMAKE_INSTALL_PREFIX PROPERTY VALUE "${CMAKE_BINARY_DIR}/OrcaSlicer")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
set(IS_CLANG_CL TRUE)
|
||||
|
||||
@@ -220,9 +101,7 @@ if (MSVC)
|
||||
# /bigobj (Increase Number of Sections in .Obj file)
|
||||
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
|
||||
# Generate symbols at every build target, even for the release.
|
||||
# -Zm520 fixes error C3859 but forces the compiler to pre-allocate that memory for every translation unit regardless
|
||||
# combining /Zi with /FS frees up a significant amount of memory pressure across all parallel compile jobs and makes /MP faster overall.
|
||||
add_compile_options(-bigobj /Zi /FS)
|
||||
add_compile_options(-bigobj -Zm520 /Zi)
|
||||
# Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
|
||||
#FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
|
||||
add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
|
||||
@@ -230,84 +109,35 @@ if (MSVC)
|
||||
# C4244: 'conversion' conversion from 'type1' to 'type2', possible loss of data. An integer type is converted to a smaller integer type.
|
||||
# C4267: The compiler detected a conversion from size_t to a smaller type.
|
||||
add_compile_options(/wd4244 /wd4267)
|
||||
# Disable warnings on comparison of unsigned and signed
|
||||
# C4018: signed/unsigned mismatch
|
||||
add_compile_options(/wd4018)
|
||||
# Prevent linker restart when TBB (or other deps) built with /GL are linked
|
||||
# Make your full (clean) build slower because it enables link-time code generation across all translation units.
|
||||
# helps incremental builds by preventing the double-link restart from TBB
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15)
|
||||
add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE _HAS_AUTO_PTR_ETC=0)
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
add_compile_options(-Wa,-mbig-obj)
|
||||
endif ()
|
||||
|
||||
if (NOT MSVC)
|
||||
# ARMs (Raspberry PI) use an unsigned char by default. Let's make it consistent for OrcaSlicer on all platforms.
|
||||
# ARMs (Raspberry PI) use an unsigned char by default. Let's make it consistent for BambuStudio on all platforms.
|
||||
add_compile_options(-fsigned-char)
|
||||
endif ()
|
||||
|
||||
if ("${DEP_BUILD_DIR}" STREQUAL "")
|
||||
get_filename_component(BIN_DIR_NAME ${CMAKE_BINARY_DIR} NAME)
|
||||
if (APPLE AND BIN_DIR_NAME STREQUAL "${CMAKE_OSX_ARCHITECTURES}")
|
||||
file(RELATIVE_PATH BIN_DIR_NAME ${CMAKE_BINARY_DIR}/../.. ${CMAKE_BINARY_DIR})
|
||||
endif ()
|
||||
set(DEP_BUILD_DIR "${CMAKE_SOURCE_DIR}/deps/${BIN_DIR_NAME}" CACHE PATH "Path to dependencies build directory" FORCE)
|
||||
message(STATUS "DEP_BUILD_DIR: ${DEP_BUILD_DIR} (generated automatically and saved to cache)")
|
||||
set(AUTOGENERATED_DEP_BUILD_DIR ${DEP_BUILD_DIR} CACHE PATH "Provides the last autogenerated DEP_BUILD_DIR" FORCE)
|
||||
else ()
|
||||
message(STATUS "DEP_BUILD_DIR: ${DEP_BUILD_DIR} (from cache or command line)")
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_PREFIX_PATH}" STREQUAL "" OR "${CMAKE_PREFIX_PATH}" STREQUAL "${AUTOGENERATED_PREFIX_PATH}")
|
||||
if (DEFINED AUTOGENERATED_DEP_BUILD_DIR AND NOT "${DEP_BUILD_DIR}" STREQUAL "${AUTOGENERATED_DEP_BUILD_DIR}")
|
||||
message(STATUS "CMAKE_PREFIX_PATH is being re-generated due to DEP_BUILD_DIR being manually updated")
|
||||
set(REGEN_DESTDIR TRUE)
|
||||
unset(AUTOGENERATED_DEP_BUILD_DIR CACHE)
|
||||
endif ()
|
||||
else ()
|
||||
unset(AUTOGENERATED_PREFIX_PATH CACHE)
|
||||
endif ()
|
||||
|
||||
# Display and check CMAKE_PREFIX_PATH
|
||||
if ("${CMAKE_PREFIX_PATH}" STREQUAL "" OR REGEN_DESTDIR)
|
||||
set(CMAKE_PREFIX_PATH "${DEP_BUILD_DIR}/OrcaSlicer_dep/usr/local" CACHE PATH "Path to dependencies install directory" FORCE)
|
||||
message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH} (generated automatically and saved to cache)")
|
||||
set(AUTOGENERATED_PREFIX_PATH ${CMAKE_PREFIX_PATH} CACHE STRING "Provides the last autogenerated CMAKE_PREFIX_PATH" FORCE)
|
||||
unset(REGEN_DESTDIR CACHE)
|
||||
else ()
|
||||
message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}")
|
||||
if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "")
|
||||
message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH} (from cache or command line)")
|
||||
endif ()
|
||||
set(PREFIX_PATH_CHECK ${CMAKE_PREFIX_PATH})
|
||||
|
||||
# the CMAKE_PREFIX_PATH environment variable is separate from the CMAKE_PREFIX_PATH cache variable and provides additional paths to search for libraries.
|
||||
if (NOT "$ENV{CMAKE_PREFIX_PATH}" STREQUAL "")
|
||||
set(PREFIX_PATH_CHECK ${CMAKE_PREFIX_PATH})
|
||||
elseif (NOT "$ENV{CMAKE_PREFIX_PATH}" STREQUAL "")
|
||||
message(STATUS "CMAKE_PREFIX_PATH: $ENV{CMAKE_PREFIX_PATH} (from environment)")
|
||||
list(APPEND PREFIX_PATH_CHECK $ENV{CMAKE_PREFIX_PATH})
|
||||
set(PREFIX_PATH_CHECK $ENV{CMAKE_PREFIX_PATH})
|
||||
else ()
|
||||
message(STATUS "CMAKE_PREFIX_PATH: (default)")
|
||||
endif ()
|
||||
|
||||
# Check all directories in CMAKE_PREFIX_PATH variables
|
||||
foreach (DIR ${PREFIX_PATH_CHECK})
|
||||
if (NOT EXISTS "${DIR}")
|
||||
message(WARNING "CMAKE_PREFIX_PATH element doesn't exist: ${DIR}")
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_MACOSX_RPATH ON CACHE BOOL "")
|
||||
set(CMAKE_MACOSX_BUNDLE ON CACHE BOOL "")
|
||||
endif ()
|
||||
|
||||
if (APPLE AND CMAKE_MACOSX_RPATH AND "${CMAKE_INSTALL_RPATH}" STREQUAL "")
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
|
||||
# Add our own cmake module path.
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/)
|
||||
message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
|
||||
@@ -321,7 +151,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT WIN32)
|
||||
# Add DEBUG flags to debug builds.
|
||||
add_compile_definitions("$<IF:$<CONFIG:Debug>,DEBUG,NDEBUG>")
|
||||
add_compile_options("$<$<CONFIG:DEBUG>:-DDEBUG>")
|
||||
endif()
|
||||
|
||||
# To be able to link libslic3r with the Perl XS module.
|
||||
@@ -330,44 +160,39 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory.
|
||||
# We pick it from environment if it is not defined in another way
|
||||
# ORCA: Removed Netfabb STL fixing service support in favor of CGAL.
|
||||
# if(WIN32)
|
||||
# if(NOT DEFINED WIN10SDK_PATH)
|
||||
# if(DEFINED ENV{WIN10SDK_PATH})
|
||||
# set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||
# endif()
|
||||
# endif()
|
||||
# if(DEFINED WIN10SDK_PATH)
|
||||
# #BBS: modify win10sdk_path
|
||||
# if (EXISTS "${WIN10SDK_PATH}/winrt/windows.graphics.printing3d.h")
|
||||
# set(WIN10SDK_INCLUDE_PATH "${WIN10SDK_PATH}")
|
||||
# else()
|
||||
# message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||
# message("${WIN10SDK_PATH}/winrt/windows.graphics.printing3d.h was not found")
|
||||
# message("STL fixing by the Netfabb service will not be compiled")
|
||||
# unset(WIN10SDK_PATH)
|
||||
# endif()
|
||||
# else()
|
||||
# # Try to use the default Windows 10 SDK path.
|
||||
# if (DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKVersion})
|
||||
# set(WIN10SDK_INCLUDE_PATH "$ENV{WindowsSdkDir}/Include/$ENV{WindowsSDKVersion}")
|
||||
# else ()
|
||||
# set(WIN10SDK_INCLUDE_PATH "C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0")
|
||||
# endif ()
|
||||
# if (NOT EXISTS "${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h")
|
||||
# message("${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h was not found")
|
||||
# message("STL fixing by the Netfabb service will not be compiled")
|
||||
# unset(WIN10SDK_INCLUDE_PATH)
|
||||
# endif()
|
||||
# endif()
|
||||
# if(WIN10SDK_INCLUDE_PATH)
|
||||
# message("Building with Win10 Netfabb STL fixing service support")
|
||||
# add_definitions(-DHAS_WIN10SDK)
|
||||
# include_directories(SYSTEM "${WIN10SDK_INCLUDE_PATH}")
|
||||
# else()
|
||||
# message("Building without Win10 Netfabb STL fixing service support")
|
||||
# endif()
|
||||
# endif()
|
||||
if(WIN32)
|
||||
if(NOT DEFINED WIN10SDK_PATH)
|
||||
if(DEFINED ENV{WIN10SDK_PATH})
|
||||
set(WIN10SDK_PATH "$ENV{WIN10SDK_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
if(DEFINED WIN10SDK_PATH)
|
||||
#BBS: modify win10sdk_path
|
||||
if (EXISTS "${WIN10SDK_PATH}/winrt/windows.graphics.printing3d.h")
|
||||
set(WIN10SDK_INCLUDE_PATH "${WIN10SDK_PATH}")
|
||||
else()
|
||||
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||
message("${WIN10SDK_PATH}/winrt/windows.graphics.printing3d.h was not found")
|
||||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_PATH)
|
||||
endif()
|
||||
else()
|
||||
# Try to use the default Windows 10 SDK path.
|
||||
set(WIN10SDK_INCLUDE_PATH "$ENV{WindowsSdkDir}/Include/$ENV{WindowsSDKVersion}")
|
||||
if (NOT EXISTS "${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h")
|
||||
message("${WIN10SDK_INCLUDE_PATH}/winrt/windows.graphics.printing3d.h was not found")
|
||||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_INCLUDE_PATH)
|
||||
endif()
|
||||
endif()
|
||||
if(WIN10SDK_INCLUDE_PATH)
|
||||
message("Building with Win10 Netfabb STL fixing service support")
|
||||
add_definitions(-DHAS_WIN10SDK)
|
||||
include_directories("${WIN10SDK_INCLUDE_PATH}")
|
||||
else()
|
||||
message("Building without Win10 Netfabb STL fixing service support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
message("OS X SDK Path: ${CMAKE_OSX_SYSROOT}")
|
||||
@@ -381,12 +206,17 @@ endif ()
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||
# Workaround for an old CMake, which does not understand CMAKE_CXX_STANDARD.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
endif()
|
||||
|
||||
# Boost on Raspberry-Pi does not link to pthreads.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(DBus REQUIRED)
|
||||
include_directories(SYSTEM ${DBUS_INCLUDE_DIRS})
|
||||
include_directories(${DBUS_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||
@@ -403,22 +233,6 @@ if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMP
|
||||
# On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error.
|
||||
add_compile_options(-Werror=return-type)
|
||||
|
||||
# Since some portions of code are just commented out or put under conditional compilation, there are
|
||||
# a bunch of warning related to unused functions and variables. Suppress those warnings to not pollute
|
||||
# compilers diagnostics output with warnings we not going to look at
|
||||
add_compile_options(-Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-label -Wno-unused-local-typedefs)
|
||||
|
||||
# Ignore signed/unsigned comparison warnings
|
||||
add_compile_options(-Wno-sign-compare)
|
||||
|
||||
# The mismatch of tabs and spaces throughout the project can sometimes
|
||||
# cause this warning to appear even though the indentation is fine.
|
||||
# Some includes also cause the warning
|
||||
add_compile_options(-Wno-misleading-indentation)
|
||||
|
||||
# Disable warning if enum value does not have a corresponding case in switch statement
|
||||
add_compile_options(-Wno-switch)
|
||||
|
||||
# removes LOTS of extraneous Eigen warnings (GCC only supports it since 6.1)
|
||||
# https://eigen.tuxfamily.org/bz/show_bug.cgi?id=1221
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.0)
|
||||
@@ -432,38 +246,14 @@ if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMP
|
||||
add_compile_options(-Wno-deprecated-declarations)
|
||||
endif()
|
||||
|
||||
if((${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang") AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 15)
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag(-Wno-error=enum-constexpr-conversion HAS_WNO_ERROR_ENUM_CONSTEXPR_CONV)
|
||||
if(HAS_WNO_ERROR_ENUM_CONSTEXPR_CONV)
|
||||
add_compile_options(-Wno-error=enum-constexpr-conversion)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#GCC generates loads of -Wunknown-pragmas when compiling igl. The fix is not easy due to a bug in gcc, see
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943 or
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
|
||||
# We will turn the warning of for GCC for now:
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# GCC generates loads of -Wunknown-pragmas when compiling igl. The fix is not easy due to a bug in gcc, see
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943 or
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
|
||||
# We will turn the warning of for GCC for now:
|
||||
add_compile_options(-Wno-unknown-pragmas)
|
||||
endif()
|
||||
|
||||
# Compress the debug info with zstd to save space in Flatpak CI builds
|
||||
if(FLATPAK)
|
||||
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.0) OR
|
||||
("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0))
|
||||
add_compile_options(-gz=zstd)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=template-id-cdtor" )
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
@@ -476,8 +266,6 @@ if (SLIC3R_ASAN)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address")
|
||||
else()
|
||||
add_compile_definitions(_DISABLE_STRING_ANNOTATION=1 _DISABLE_VECTOR_ANNOTATION=1)
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
@@ -490,12 +278,6 @@ if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=partial-availability -Werror=unguarded-availability -Werror=unguarded-availability-new")
|
||||
endif ()
|
||||
|
||||
if(MSVC)
|
||||
# Ignore truncating casts in initializers & constructors
|
||||
# https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4305
|
||||
add_compile_options(/wd4305)
|
||||
endif()
|
||||
|
||||
# Where all the bundled libraries reside?
|
||||
set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(LIBDIR_BIN ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
@@ -503,18 +285,18 @@ message(STATUS "LIBDIR: ${LIBDIR}")
|
||||
message(STATUS "LIBDIR_BIN: ${LIBDIR_BIN}")
|
||||
|
||||
# For the bundled boost libraries (boost::nowide)
|
||||
include_directories(SYSTEM ${LIBDIR})
|
||||
include_directories(${LIBDIR})
|
||||
# For generated header files
|
||||
include_directories(SYSTEM ${LIBDIR_BIN}/dev-utils/platform)
|
||||
include_directories(${LIBDIR_BIN}/platform)
|
||||
# For ligigl
|
||||
include_directories(SYSTEM ${LIBDIR}/libigl)
|
||||
include_directories(${LIBDIR}/libigl)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
|
||||
if(MSVC)
|
||||
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
|
||||
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x602 -DBOOST_SYSTEM_USE_UTF8 )
|
||||
# Force the source code encoding to UTF-8. See OrcaSlicer GH pull request #5583
|
||||
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -DBOOST_SYSTEM_USE_UTF8 )
|
||||
# Force the source code encoding to UTF-8. See BambuStudio GH pull request #5583
|
||||
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
endif(MSVC)
|
||||
@@ -526,65 +308,38 @@ add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO)
|
||||
add_definitions(-DwxNO_UNSAFE_WXSTRING_CONV)
|
||||
|
||||
if (SLIC3R_PROFILE)
|
||||
message("OrcaSlicer will be built with a Shiny invasive profiler")
|
||||
message("BambuStudio will be built with a Shiny invasive profiler")
|
||||
add_definitions(-DSLIC3R_PROFILE)
|
||||
endif ()
|
||||
|
||||
# Disable optimization for RelWithDebInfo
|
||||
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "/O2")
|
||||
string(REGEX REPLACE "/O2" "/Od" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
# Disable optimization even with debugging on.
|
||||
if (0)
|
||||
message(STATUS "Perl compiled without optimization. Disabling optimization for the BambuStudio build.")
|
||||
message("Old CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message("Old CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
message("Old CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS_RELEASE "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_CXX_FLAGS "/MD /Od /Zi /EHsc /DWIN32 /DTBB_USE_ASSERT")
|
||||
set(CMAKE_C_FLAGS "/MD /Od /Zi /DWIN32 /DTBB_USE_ASSERT")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "/O2")
|
||||
string(REGEX REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "-O2")
|
||||
string(REGEX REPLACE "-O2" "-O0" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "-O2")
|
||||
string(REGEX REPLACE "-O2" "-O0" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if(CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "/Ob1")
|
||||
string(REGEX REPLACE "/Ob1" "/Ob0" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
if(CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "/Ob1")
|
||||
string(REGEX REPLACE "/Ob1" "/Ob0" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /RTC1")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /RTC1")
|
||||
endif()
|
||||
|
||||
list(REMOVE_DUPLICATES CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
list(REMOVE_DUPLICATES CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
|
||||
# Find and configure boost
|
||||
if(SLIC3R_STATIC)
|
||||
# Use static boost libraries.
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
# Use boost libraries linked statically to the C++ runtime.
|
||||
# set(Boost_USE_STATIC_RUNTIME ON)
|
||||
else()
|
||||
add_definitions(-DBOOST_LOG_DYN_LINK)
|
||||
endif()
|
||||
#set(Boost_DEBUG ON)
|
||||
# set(Boost_COMPILER "-mgw81")
|
||||
# boost::process was introduced first in version 1.64.0,
|
||||
# boost::beast::detail::base64 was introduced first in version 1.66.0
|
||||
if(POLICY CMP0167)
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
endif()
|
||||
set(Boost_NO_SYSTEM_PATHS TRUE)
|
||||
find_package(Boost 1.83.0 REQUIRED COMPONENTS system filesystem thread log log_setup locale regex chrono atomic date_time iostreams program_options nowide)
|
||||
|
||||
# Find and configure Eigen3
|
||||
find_package(Eigen3 5.0.1 REQUIRED)
|
||||
set(MINIMUM_BOOST_VERSION "1.66.0")
|
||||
set(_boost_components "system;filesystem;thread;log;locale;regex;chrono;atomic;date_time;iostreams")
|
||||
find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS ${_boost_components})
|
||||
|
||||
add_library(boost_libs INTERFACE)
|
||||
add_library(boost_headeronly INTERFACE)
|
||||
@@ -601,7 +356,7 @@ endif()
|
||||
function(slic3r_remap_configs targets from_Cfg to_Cfg)
|
||||
if(MSVC)
|
||||
string(TOUPPER ${from_Cfg} from_CFG)
|
||||
|
||||
|
||||
foreach(tgt ${targets})
|
||||
if(TARGET ${tgt})
|
||||
set_target_properties(${tgt} PROPERTIES MAP_IMPORTED_CONFIG_${from_CFG} ${to_Cfg})
|
||||
@@ -610,17 +365,36 @@ function(slic3r_remap_configs targets from_Cfg to_Cfg)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
target_include_directories(boost_headeronly SYSTEM INTERFACE ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(boost_libs INTERFACE boost_headeronly ${Boost_LIBRARIES})
|
||||
if(TARGET Boost::system)
|
||||
message(STATUS "Boost::boost exists")
|
||||
target_link_libraries(boost_headeronly INTERFACE Boost::boost)
|
||||
|
||||
# Only from cmake 3.12
|
||||
# list(TRANSFORM _boost_components PREPEND Boost:: OUTPUT_VARIABLE _boost_targets)
|
||||
set(_boost_targets "")
|
||||
foreach(comp ${_boost_components})
|
||||
list(APPEND _boost_targets "Boost::${comp}")
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(boost_libs INTERFACE
|
||||
boost_headeronly # includes the custom compile definitions as well
|
||||
${_boost_targets}
|
||||
)
|
||||
slic3r_remap_configs("${_boost_targets}" RelWithDebInfo Release)
|
||||
else()
|
||||
target_include_directories(boost_headeronly INTERFACE ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(boost_libs INTERFACE boost_headeronly ${Boost_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# Find and configure intel-tbb
|
||||
if(SLIC3R_STATIC)
|
||||
set(TBB_STATIC 1)
|
||||
endif()
|
||||
set(TBB_DEBUG 1)
|
||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release "")
|
||||
find_package(TBB REQUIRED)
|
||||
# include_directories(SYSTEM ${TBB_INCLUDE_DIRS})
|
||||
# include_directories(${TBB_INCLUDE_DIRS})
|
||||
# add_definitions(${TBB_DEFINITIONS})
|
||||
# if(MSVC)
|
||||
# # Suppress implicit linking of the TBB libraries by the Visual Studio compiler.
|
||||
@@ -630,9 +404,11 @@ find_package(TBB REQUIRED)
|
||||
# add_definitions(-DTBB_USE_CAPTURED_EXCEPTION=0)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if (APPLE)
|
||||
find_package(CURL CONFIG REQUIRED)
|
||||
else()
|
||||
find_package(CURL REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
|
||||
endif()
|
||||
|
||||
add_library(libcurl INTERFACE)
|
||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||
@@ -663,13 +439,23 @@ if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_CURL)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
|
||||
message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
target_include_directories(libcurl SYSTEM INTERFACE ${OPENSSL_INCLUDE_DIR})
|
||||
target_include_directories(libcurl INTERFACE ${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(libcurl INTERFACE ${OPENSSL_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## OPTIONAL packages
|
||||
|
||||
# Find eigen3 or use bundled version
|
||||
if (NOT SLIC3R_STATIC)
|
||||
find_package(Eigen3 3.3)
|
||||
endif ()
|
||||
if (NOT EIGEN3_FOUND)
|
||||
set(EIGEN3_FOUND 1)
|
||||
set(EIGEN3_INCLUDE_DIR ${LIBDIR}/eigen/)
|
||||
endif ()
|
||||
include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR})
|
||||
|
||||
# Find expat or use bundled version
|
||||
# Always use the system libexpat on Linux.
|
||||
|
||||
@@ -691,43 +477,49 @@ find_package(PNG REQUIRED)
|
||||
set(OpenGL_GL_PREFERENCE "LEGACY")
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
if(APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
|
||||
set(OPENGL_LIBRARIES "-framework OpenGL" CACHE STRING "OpenGL framework" FORCE)
|
||||
# Find glew or use bundled version
|
||||
if (SLIC3R_STATIC AND NOT SLIC3R_STATIC_EXCLUDE_GLEW)
|
||||
set(GLEW_USE_STATIC_LIBS ON)
|
||||
set(GLEW_VERBOSE ON)
|
||||
endif()
|
||||
|
||||
find_package(GLEW)
|
||||
if (NOT TARGET GLEW::GLEW)
|
||||
message(STATUS "GLEW not found, using bundled version.")
|
||||
add_library(glew STATIC ${LIBDIR}/glew/src/glew.c)
|
||||
set(GLEW_FOUND TRUE)
|
||||
set(GLEW_INCLUDE_DIRS ${LIBDIR}/glew/include/)
|
||||
target_compile_definitions(glew PUBLIC GLEW_STATIC)
|
||||
target_include_directories(glew PUBLIC ${GLEW_INCLUDE_DIRS})
|
||||
add_library(GLEW::GLEW ALIAS glew)
|
||||
endif ()
|
||||
|
||||
find_package(glfw3 REQUIRED)
|
||||
|
||||
# Find the Cereal serialization library
|
||||
find_package(cereal REQUIRED)
|
||||
if (NOT TARGET cereal::cereal)
|
||||
set_target_properties(cereal PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||
add_library(cereal::cereal ALIAS cereal)
|
||||
else ()
|
||||
set_target_properties(cereal::cereal PROPERTIES IMPORTED_GLOBAL TRUE)
|
||||
endif ()
|
||||
|
||||
# l10n
|
||||
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/i18n")
|
||||
set(BBL_L18N_DIR "${CMAKE_CURRENT_SOURCE_DIR}/localization/i18n")
|
||||
set(BBL_L18N_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bbl/i18n")
|
||||
add_custom_target(gettext_make_pot
|
||||
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_CTX:1,2c --keyword=_CTX_utf8:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --no-location --debug --boost
|
||||
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --no-location --debug --boost
|
||||
-f "${BBL_L18N_DIR}/list.txt"
|
||||
-o "${BBL_L18N_DIR}/OrcaSlicer.pot"
|
||||
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${BBL_L18N_DIR}
|
||||
-o "${BBL_L18N_DIR}/BambuStudio.pot"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Generate pot file from strings in the source tree"
|
||||
)
|
||||
add_custom_target(gettext_merge_po_with_pot
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Merge localization po with new generated pot file"
|
||||
COMMENT "Merge localization po with new generted pot file"
|
||||
)
|
||||
file(GLOB BBL_L10N_PO_FILES "${BBL_L18N_DIR}/*/OrcaSlicer*.po")
|
||||
file(GLOB BBL_L10N_PO_FILES "${BBL_L18N_DIR}/*/BambuStudio*.po")
|
||||
foreach(po_file ${BBL_L10N_PO_FILES})
|
||||
GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
|
||||
SET(po_new_file "${po_dir}/OrcaSlicer_.po")
|
||||
SET(po_new_file "${po_dir}/BambuStudio_.po")
|
||||
add_custom_command(
|
||||
TARGET gettext_merge_po_with_pot PRE_BUILD
|
||||
COMMAND msgmerge -N -o ${po_file} ${po_file} "${BBL_L18N_DIR}/OrcaSlicer.pot"
|
||||
COMMAND msgmerge -N -o ${po_file} ${po_file} "${BBL_L18N_DIR}/BambuStudio.pot"
|
||||
DEPENDS ${po_file}
|
||||
)
|
||||
endforeach()
|
||||
@@ -735,11 +527,11 @@ add_custom_target(gettext_po_to_mo
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Generate localization po files (binary) from mo files (texts)"
|
||||
)
|
||||
file(GLOB L10N_PO_FILES "${BBL_L18N_DIR}/*/OrcaSlicer*.po")
|
||||
file(GLOB L10N_PO_FILES "${BBL_L18N_DIR}/*/BambuStudio*.po")
|
||||
foreach(po_file ${BBL_L10N_PO_FILES})
|
||||
GET_FILENAME_COMPONENT(SECOND_FOLDER_ABSOLUTE ${po_file} DIRECTORY)
|
||||
string(REGEX REPLACE ".*/(.*)" "\\1" po_dir "${SECOND_FOLDER_ABSOLUTE}" )
|
||||
SET(mo_file "${L10N_DIR}/${po_dir}/OrcaSlicer.mo")
|
||||
SET(mo_file "${L10N_DIR}/${po_dir}/BambuStudio.mo")
|
||||
add_custom_command(
|
||||
TARGET gettext_po_to_mo PRE_BUILD
|
||||
COMMAND msgfmt ARGS --check-format -o ${mo_file} ${po_file}
|
||||
@@ -766,29 +558,13 @@ else ()
|
||||
"OpenVDB installation with the OPENVDB_FIND_MODULE_PATH cache variable.")
|
||||
endif ()
|
||||
|
||||
find_path(SPNAV_INCLUDE_DIR spnav.h)
|
||||
if (SPNAV_INCLUDE_DIR)
|
||||
find_library(SPNAV_LIB NAMES libspnav.a) # Force linking libspnav statically
|
||||
if (SPNAV_LIB)
|
||||
add_definitions(-DHAVE_SPNAV)
|
||||
message(STATUS "SPNAV library found")
|
||||
else()
|
||||
message(STATUS "SPNAV library NOT found, Spacenavd not supported")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "SPNAV library NOT found, Spacenavd not supported")
|
||||
endif()
|
||||
|
||||
set(TOP_LEVEL_PROJECT_DIR ${PROJECT_SOURCE_DIR})
|
||||
function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64")
|
||||
set(_arch "x64")
|
||||
elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "X86")
|
||||
set(_arch "x86")
|
||||
elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ARM64")
|
||||
set(_arch "arm64")
|
||||
else ()
|
||||
message(FATAL_ERROR "Unable to detect architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
function(bambustudio_copy_dlls target config postfix output_dlls)
|
||||
if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(_bits 64)
|
||||
elseif ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
|
||||
set(_bits 32)
|
||||
endif ()
|
||||
|
||||
get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
@@ -805,9 +581,9 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
message ("set out_dir to CMAKE_CURRENT_BINARY_DIR: ${_out_dir}")
|
||||
endif ()
|
||||
|
||||
file(COPY ${TOP_LEVEL_PROJECT_DIR}/deps/GMP/gmp/lib/win-${_arch}/libgmp-10.dll
|
||||
${TOP_LEVEL_PROJECT_DIR}/deps/MPFR/mpfr/lib/win-${_arch}/libmpfr-4.dll
|
||||
${TOP_LEVEL_PROJECT_DIR}/deps/WebView2/lib/win-${_arch}/WebView2Loader.dll
|
||||
file(COPY ${TOP_LEVEL_PROJECT_DIR}/deps/GMP/gmp/lib/win${_bits}/libgmp-10.dll
|
||||
${TOP_LEVEL_PROJECT_DIR}/deps/MPFR/mpfr/lib/win${_bits}/libmpfr-4.dll
|
||||
${TOP_LEVEL_PROJECT_DIR}/deps/WebView2/lib/win${_bits}/WebView2Loader.dll
|
||||
DESTINATION ${_out_dir})
|
||||
|
||||
file(COPY ${CMAKE_PREFIX_PATH}/bin/occt/TKBO.dll
|
||||
@@ -836,7 +612,6 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
${CMAKE_PREFIX_PATH}/bin/occt/TKXCAF.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/occt/TKXDESTEP.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/occt/TKXSBase.dll
|
||||
${CMAKE_PREFIX_PATH}/bin/freetype.dll
|
||||
DESTINATION ${_out_dir})
|
||||
|
||||
set(${output_dlls}
|
||||
@@ -871,95 +646,58 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
${_out_dir}/TKXDESTEP.dll
|
||||
${_out_dir}/TKXSBase.dll
|
||||
|
||||
${_out_dir}/freetype.dll
|
||||
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
|
||||
add_subdirectory(deps_src)
|
||||
# libslic3r, BambuStudio GUI and the BambuStudio executable.
|
||||
add_subdirectory(src)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OrcaSlicer_app_gui)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT BambuStudio_app_gui)
|
||||
|
||||
add_dependencies(gettext_make_pot hintsToPot)
|
||||
# Perl bindings, currently only used for the unit / integration tests of libslic3r.
|
||||
# Also runs the unit / integration tests.
|
||||
#FIXME Port the tests into C++ to finally get rid of the Perl!
|
||||
if (SLIC3R_PERL_XS)
|
||||
add_subdirectory(xs)
|
||||
endif ()
|
||||
|
||||
if(SLIC3R_BUILD_SANDBOXES)
|
||||
add_subdirectory(sandboxes)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTS)
|
||||
if(SLIC3R_BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
set(SLIC3R_APP_CMD "orca-slicer")
|
||||
configure_file(${LIBDIR}/dev-utils/platform/unix/build_appimage.sh.in ${CMAKE_CURRENT_BINARY_DIR}/build_appimage.sh USE_SOURCE_PERMISSIONS @ONLY)
|
||||
option(BUILD_BBS_TEST_TOOLS "Build bbs test tools" OFF)
|
||||
if(BUILD_BBS_TEST_TOOLS)
|
||||
add_subdirectory(bbs_test_tools)
|
||||
endif()
|
||||
|
||||
|
||||
# Resources install target, configure fhs.hpp on UNIX
|
||||
if (WIN32)
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "./resources")
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
install (PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ".")
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
||||
elseif (SLIC3R_FHS)
|
||||
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
|
||||
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/OrcaSlicer")
|
||||
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/BambuStudio")
|
||||
install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
|
||||
PATTERN "*/udev" EXCLUDE
|
||||
)
|
||||
install(FILES src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||
install(FILES src/platform/unix/BambuStudio.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
|
||||
foreach(SIZE 32 128 192)
|
||||
install(FILES ${SLIC3R_RESOURCES_DIR}/images/OrcaSlicer_${SIZE}px.png
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME OrcaSlicer.png
|
||||
install(FILES ${SLIC3R_RESOURCES_DIR}/images/BambuStudio_${SIZE}px.png
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME BambuStudio.png
|
||||
)
|
||||
endforeach()
|
||||
install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/udev/ DESTINATION lib/udev/rules.d)
|
||||
elseif (CMAKE_MACOSX_BUNDLE)
|
||||
# install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/OrcaSlicer.app/Contents/resources")
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/BambuStudio.app/Contents/resources")
|
||||
else ()
|
||||
install(FILES src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications)
|
||||
install(FILES src/platform/unix/BambuStudio.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications)
|
||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
||||
endif ()
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.txt DESTINATION ".")
|
||||
configure_file(${LIBDIR}/dev-utils/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/dev-utils/platform/unix/fhs.hpp)
|
||||
|
||||
set (CPACK_PACKAGE_NAME "OrcaSlicer")
|
||||
set (CPACK_PACKAGE_VENDOR "SoftFever")
|
||||
set (CPACK_PACKAGE_VERSION_MAJOR "${ORCA_VERSION_MAJOR}")
|
||||
set (CPACK_PACKAGE_VERSION_MINOR "${ORCA_VERSION_MINOR}")
|
||||
set (CPACK_PACKAGE_VERSION_PATCH "${ORCA_VERSION_PATCH}")
|
||||
set (CPACK_PACKAGE_FILE_NAME "OrcaSlicer_Windows_Installer_V${SoftFever_VERSION}")
|
||||
# Suffix the Windows installer with its target arch so the x64 and arm64 builds
|
||||
# produce distinct filenames (matches ARCH_SUFFIX in build_orca.yml). Same
|
||||
# CMAKE_SYSTEM_PROCESSOR mapping used by orcaslicer_copy_dlls() above.
|
||||
if (WIN32)
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
string (APPEND CPACK_PACKAGE_FILE_NAME "_arm64")
|
||||
else ()
|
||||
string (APPEND CPACK_PACKAGE_FILE_NAME "_x64")
|
||||
endif ()
|
||||
endif ()
|
||||
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Orca Slicer is an open source slicer for FDM printers")
|
||||
set (CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/OrcaSlicer_3/OrcaSlicer")
|
||||
set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set (CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/images\\\\OrcaSlicer.ico")
|
||||
set (CPACK_NSIS_MUI_ICON "${CPACK_PACKAGE_ICON}")
|
||||
set (CPACK_NSIS_MUI_UNIICON "${CPACK_PACKAGE_ICON}")
|
||||
set (CPACK_NSIS_INSTALLED_ICON_NAME "$INSTDIR\\\\orca-slicer.exe")
|
||||
set (CPACK_PACKAGE_CHECKSUM SHA256)
|
||||
set (CPACK_PACKAGE_INSTALL_REGISTRY_KEY "OrcaSlicer")
|
||||
set (CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
set (CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||
# set (CPACK_NSIS_MODIFY_PATH "ON")
|
||||
set(CPACK_PACKAGE_EXECUTABLES "orca-slicer;OrcaSlicer")
|
||||
set(CPACK_CREATE_DESKTOP_LINKS "orca-slicer")
|
||||
set (CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt) # must also include in install command
|
||||
|
||||
set(CPACK_WIX_UPGRADE_GUID "058245e8-20e0-4a95-9ab7-1acfe17ad511")
|
||||
set(CPACK_GENERATOR NSIS)
|
||||
include(CPack)
|
||||
configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp)
|
||||
|
||||
309
README.md
@@ -1,237 +1,80 @@
|
||||
<div align="center">
|
||||
|
||||
<picture>
|
||||
<img alt="OrcaSlicer logo" src="resources/images/OrcaSlicer.png" width="15%" height="15%">
|
||||
</picture>
|
||||
|
||||
<a href="https://trendshift.io/repositories/15552" target="_blank"><img src="https://trendshift.io/api/badge/repositories/15552" alt="OrcaSlicer%2FOrcaSlicer | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
|
||||
[](https://github.com/OrcaSlicer/OrcaSlicer/stargazers) [](https://github.com/OrcaSlicer/OrcaSlicer/actions/workflows/build_all.yml)
|
||||
|
||||
OrcaSlicer: an open source Next-Gen Slicing Software for Precision 3D Prints.
|
||||
Optimize your prints with ultra-fast slicing, intelligent support generation, and seamless printer compatibility—engineered for perfection.
|
||||
<h3>
|
||||
|
||||
# Official links and community
|
||||
|
||||
#### Official Website:
|
||||
|
||||
<a href="https://www.orcaslicer.com/" style="font-size:2em;">OrcaSlicer.com</a>
|
||||
|
||||
#### Github Repository:
|
||||
|
||||
<a href="https://github.com/OrcaSlicer/OrcaSlicer"><img src="https://img.shields.io/badge/OrcaSlicer-181717?style=flat&logo=github&logoColor=white" width="200" alt="GitHub Logo"/> </a>
|
||||
|
||||
#### Follow us:
|
||||
|
||||
<a href="https://twitter.com/real_OrcaSlicer"><img src="https://img.shields.io/badge/real__OrcaSlicer-000000?style=flat&logo=x&logoColor=white" width="200" alt="X Logo"/> </a>
|
||||
<a href="https://www.youtube.com/@OfficialOrcaSlicer"><img src="https://img.shields.io/badge/OfficialOrcaSlicer-FF0000?style=flat&logo=youtube&logoColor=white" width="200" alt="YouTube Logo"/> </a>
|
||||
|
||||
#### Join our Discord community:
|
||||
|
||||
<a href="https://discord.gg/P4VE9UY9gJ"><img src="https://img.shields.io/badge/-Discord-5865F2?style=flat&logo=discord&logoColor=fff" width="200" alt="discord logo"/> </a>
|
||||
|
||||
<table border="2" style="border-color: #ffa500; background-color:rgb(232, 220, 180); color: #856404;">
|
||||
<tr>
|
||||
<td>
|
||||
<strong>⚠️ CAUTION:</strong><br>
|
||||
Several clickbait and malicious websites, such as <b>orca-slicer[.]com</b> and <b>orcaslicer[.]net</b>, are pretending to be the official OrcaSlicer site. These sites may redirect you to dangerous downloads or contain misleading information.<br>
|
||||
<b>Our only official website is <a href="https://www.orcaslicer.com/">www.orcaslicer.com</a>.</b><br><br>
|
||||
If you come across any of these in search results, please <b>report them</b> as unsafe or phishing to help keep the community secure with:<br>
|
||||
- <a href="https://safebrowsing.google.com/safebrowsing/report_phish/">Google Safe Browsing</a><br>
|
||||
- <a href="https://www.microsoft.com/en-us/wdsi/support/report-unsafe-site">Microsoft Security Intelligence</a><br>
|
||||
- <a href="https://ipthreat.net/tools/reportphishing">IPThreat</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
# Main features
|
||||
|
||||
- **[Advanced Calibration Tools](https://www.orcaslicer.com/wiki/calibration_guide)**
|
||||
Comprehensive suite: temperature towers, flow rate, retraction & more for optimal performance.
|
||||
- **[Precise Wall](https://www.orcaslicer.com/wiki/quality_settings_precision#precise-wall) and [Seam Control](https://www.orcaslicer.com/wiki/quality_settings_seam)**
|
||||
Adjust outer wall spacing and apply scarf seams to enhance print accuracy.
|
||||
- **[Sandwich Mode](https://www.orcaslicer.com/wiki/quality_settings_wall_and_surfaces#innerouterinner) and [Polyholes](https://www.orcaslicer.com/wiki/quality_settings_precision#polyholes) Support**
|
||||
Use varied infill [patterns](https://www.orcaslicer.com/wiki/strength_settings_patterns) and accurate hole shapes for improved clarity.
|
||||
- **[Overhang](https://www.orcaslicer.com/wiki/quality_settings_overhangs) and [Support Optimization](https://www.orcaslicer.com/wiki#support-settings)**
|
||||
Modify geometry for printable overhangs with precise support placement.
|
||||
- **[Granular Controls and Customization](https://www.orcaslicer.com/wiki#process-settings)**
|
||||
Fine-tune print speed, layer height, pressure, and temperature with precision.
|
||||
- **Network Printer Support**
|
||||
Seamless integration with Klipper, PrusaLink, and OctoPrint for remote control.
|
||||
- **[Mouse Ear Brims](https://www.orcaslicer.com/wiki/others_settings_brim) & [Adaptive Bed Mesh](https://www.orcaslicer.com/wiki/printer_basic_information_adaptive_bed_mesh)**
|
||||
Automatic brims and adaptive mesh calibration ensure consistent adhesion.
|
||||
- **User-Friendly Interface**
|
||||
Intuitive drag-and-drop design with pre-made profiles for popular printers.
|
||||
- **[Open-Source](https://github.com/OrcaSlicer/OrcaSlicer) & [Community Driven](https://discord.gg/P4VE9UY9gJ)**
|
||||
Regular updates fueled by continuous community contributions.
|
||||
- **Wide Printer Compatibility**
|
||||
Supports a broad range of printers: Bambu Lab, Prusa, Creality, Voron, and more.
|
||||
- Additional features can be found in the [change notes](https://github.com/OrcaSlicer/OrcaSlicer/releases/).
|
||||
|
||||
# Wiki
|
||||
|
||||
The [wiki](https://www.orcaslicer.com/wiki) aims to provide a detailed explanation of the slicer settings, including how to maximize their use and how to calibrate and set up your printer.
|
||||
|
||||
- **[Access the wiki here](https://www.orcaslicer.com/wiki)**
|
||||
- **[Contribute to the wiki](https://www.orcaslicer.com/wiki/how_to_wiki)**
|
||||
|
||||
# Download
|
||||
|
||||
## Stable Release
|
||||
|
||||
📥 **[Download the Latest Stable Release](https://github.com/OrcaSlicer/OrcaSlicer/releases/latest)**
|
||||
Visit our GitHub Releases page for the latest stable version of OrcaSlicer, recommended for most users.
|
||||
|
||||
## Nightly Builds
|
||||
|
||||
🌙 **[Download the Latest Nightly Build](https://github.com/OrcaSlicer/OrcaSlicer/releases/tag/nightly-builds)**
|
||||
Explore the latest developments in OrcaSlicer with our nightly builds. Feedback on these versions is highly appreciated.
|
||||
|
||||
# How to install
|
||||
|
||||
## Windows
|
||||
|
||||
Download the **Windows Installer exe** for your preferred version from the [releases page](https://github.com/OrcaSlicer/OrcaSlicer/releases).
|
||||
|
||||
- *For convenience there is also a portable build available.*
|
||||
<details>
|
||||
<summary>Troubleshooting</summary>
|
||||
|
||||
- *If you have troubles to run the build, you might need to install following runtimes:*
|
||||
- [MicrosoftEdgeWebView2RuntimeInstallerX64](https://github.com/OrcaSlicer/OrcaSlicer/releases/download/v1.0.10-sf2/MicrosoftEdgeWebView2RuntimeInstallerX64.exe)
|
||||
- [Details of this runtime](https://aka.ms/webview2)
|
||||
- [Alternative Download Link Hosted by Microsoft](https://go.microsoft.com/fwlink/p/?LinkId=2124703)
|
||||
- [vcredist2019_x64](https://github.com/OrcaSlicer/OrcaSlicer/releases/download/v1.0.10-sf2/vcredist2019_x64.exe)
|
||||
- [Alternative Download Link Hosted by Microsoft](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
- This file may already be available on your computer if you've installed visual studio. Check the following location: `%VCINSTALLDIR%Redist\MSVC\v142`
|
||||
</details>
|
||||
|
||||
Windows Package Manager
|
||||
|
||||
```shell
|
||||
winget install --id=SoftFever.OrcaSlicer -e
|
||||
```
|
||||
|
||||
## Mac
|
||||
|
||||
1. Download the DMG for your computer: `arm64` version for Apple Silicon and `x86_64` for Intel CPU.
|
||||
2. Drag OrcaSlicer.app to Application folder.
|
||||
3. *If you want to run a build from a PR, you also need to follow the instructions below:*
|
||||
|
||||
<details>
|
||||
<summary>Quarantine</summary>
|
||||
|
||||
- Option 1 (You only need to do this once. After that the app can be opened normally.):
|
||||
- Step 1: Hold _cmd_ and right click the app, from the context menu choose **Open**.
|
||||
- Step 2: A warning window will pop up, click _Open_
|
||||
|
||||
- Option 2:
|
||||
Execute this command in terminal:
|
||||
|
||||
```shell
|
||||
xattr -dr com.apple.quarantine /Applications/OrcaSlicer.app
|
||||
```
|
||||
|
||||
- Option 3:
|
||||
- Step 1: open the app, a warning window will pop up
|
||||

|
||||
- Step 2: in `System Settings` -> `Privacy & Security`, click `Open Anyway`:
|
||||

|
||||
</details>
|
||||
|
||||
## Linux
|
||||
|
||||
### Flathub (Recommended)
|
||||
|
||||
OrcaSlicer is available through FlatHub:
|
||||
|
||||
<a href='https://flathub.org/apps/com.orcaslicer.OrcaSlicer'><img width='240' alt='Download on Flathub' src='https://dl.flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||
|
||||
Install from the command line:
|
||||
|
||||
```shell
|
||||
flatpak install flathub com.orcaslicer.OrcaSlicer
|
||||
flatpak run com.orcaslicer.OrcaSlicer
|
||||
```
|
||||
|
||||
It can also be installed through graphical software managers (KDE Discover, GNOME Software, etc.) when Flathub is enabled. Search for **OrcaSlicer** in your software center.
|
||||
|
||||
### AppImage
|
||||
|
||||
AppImages are published for both **x86_64** and **aarch64** (ARM64). Pick the file matching your CPU — the ARM64 build has `aarch64` in its name (e.g. `OrcaSlicer_Linux_AppImage_Ubuntu2404_aarch64_*.AppImage`).
|
||||
|
||||
1. Download App image from the [releases page](https://github.com/OrcaSlicer/OrcaSlicer/releases).
|
||||
2. Double click the downloaded file to run it.
|
||||
|
||||
3. If you run into trouble executing it, try this command in the terminal:
|
||||
`chmod +x /path_to_appimage/OrcaSlicer_Linux.AppImage`
|
||||
|
||||
# How to Compile
|
||||
|
||||
All updated build instructions for Windows, macOS, and Linux are now available on the official [OrcaSlicer Wiki - How to build](https://www.orcaslicer.com/wiki/how_to_build) page.
|
||||
|
||||
Please refer to the wiki to ensure you're following the latest and most accurate steps for your platform.
|
||||
|
||||
# Klipper Note
|
||||
|
||||
If you're running Klipper, it's recommended to add the following configuration to your `printer.cfg` file.
|
||||
|
||||
```gcode
|
||||
# Enable object exclusion
|
||||
[exclude_object]
|
||||
|
||||
# Enable arcs support
|
||||
[gcode_arcs]
|
||||
resolution: 0.1
|
||||
```
|
||||
|
||||
# Supports
|
||||
|
||||
**OrcaSlicer** is an open-source project and I'm deeply grateful to all my sponsors and backers.
|
||||
Their generous support enables me to purchase filaments and other essential 3D printing materials for the project.
|
||||
Thank you! :)
|
||||
|
||||
## Sponsors
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://qidi3d.com/" style="display:inline-block; border-radius:8px; background:#fff;">
|
||||
<img src="SoftFever_doc\sponsor_logos\QIDI.png" alt="QIDI" width="100" height="100">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://bigtree-tech.com/" style="display:inline-block; border-radius:8px; background:#222;">
|
||||
<img src="SoftFever_doc\sponsor_logos\BigTreeTech.png" alt="BIGTREE TECH" width="100" height="100">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Backers:
|
||||
|
||||
**Ko-fi supporters** ☕: [Backers list](https://github.com/user-attachments/files/16147016/Supporters_638561417699952499.csv)
|
||||
|
||||
## Support me
|
||||
|
||||
<a href="https://github.com/sponsors/SoftFever"><img src="https://img.shields.io/badge/GitHub%20Sponsors-30363D?style=flat&logo=GitHub-Sponsors&logoColor=EA4AAA" height="50"></a>
|
||||
<a href="https://ko-fi.com/G2G5IP3CP"><img src="https://img.shields.io/badge/Support_me_on_Ko--fi-FF5E5B?style=flat&logo=ko-fi&logoColor=white" height="50"></a>
|
||||
<a href="https://paypal.me/softfever3d"><img src="https://img.shields.io/badge/PayPal-003087?style=flat&logo=paypal&logoColor=fff" height="50"></a>
|
||||
|
||||
## Some Background
|
||||
|
||||
Open-source slicing has always been built on a tradition of collaboration and attribution. [Slic3r](https://github.com/Slic3r/Slic3r), created by Alessandro Ranellucci and the RepRap community, laid the foundation. [PrusaSlicer](https://github.com/prusa3d/PrusaSlicer) by Prusa Research built on Slic3r and acknowledged that heritage. [Bambu Studio](https://github.com/bambulab/BambuStudio) in turn forked from PrusaSlicer, and [SuperSlicer](https://github.com/supermerill/SuperSlicer) by @supermerill extended PrusaSlicer with community-driven enhancements. Each project carried the work of its predecessors forward, crediting those who came before.
|
||||
|
||||
OrcaSlicer began in that same spirit, drawing from BambuStudio, PrusaSlicer, and ideas inspired by CuraSlicer and SuperSlicer. But it has since grown far beyond its origins. Through relentless innovation — introducing advanced calibration tools, precise wall and seam control, tree supports, adaptive slicing, and hundreds of other features — OrcaSlicer has become the most widely used and actively developed open-source slicer in the 3D printing community. Many of its innovations have been adopted by other slicers, making it a driving force for the entire industry.
|
||||
|
||||
The OrcaSlicer logo was designed by community member [Justin Levine](https://github.com/jal-co).
|
||||
A modified version of Bambu Studio.
|
||||
It has following changes:
|
||||
|
||||
- Support third-party machines:
|
||||
- Voron 2.4
|
||||
- Voron Trident
|
||||
- Voron 0.1
|
||||
- Prusa MK3S
|
||||
- Export to to .gcode file.
|
||||
|
||||
Video: https://youtu.be/zCc7mVwu2xQ
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
Image credits:
|
||||
1. Voron 2.4: vorondesign.com
|
||||
2. Voron bed texture: VoronUsers/bryansj
|
||||
3. Voron 0.1: myself
|
||||
4. Prusa MK3S: Prusa3d
|
||||
|
||||
|
||||
=========================SPLIT=========================
|
||||
|
||||

|
||||
# BambuStudio
|
||||
Bambu Studio is a cutting-edge, feature-rich slicing software.
|
||||
It contains project-based workflows, systematically optimized slicing algorithms, and an easy-to-use graphic interface, bringing users an incredibly smooth printing experience.
|
||||
|
||||
Prebuilt Windows, macOS 64-bit releases are available through the [github releases page](https://github.com/bambulab/BambuStudio/releases/).
|
||||
Linux version currently is not supported.
|
||||
|
||||
Bambu Studio is based on [PrusaSlicer](https://github.com/prusa3d/PrusaSlicer) by Prusa Research, which is from [Slic3r](https://github.com/Slic3r/Slic3r) by Alessandro Ranellucci and the RepRap community.
|
||||
|
||||
See the [wiki](https://github.com/bambulab/BambuStudio/wiki) and the [documentation directory](https://github.com/bambulab/BambuStudio/tree/master/doc) for more informations.
|
||||
|
||||
# What are Bambu Studio's main features?
|
||||
Key features are:
|
||||
- Basic slicing features & GCode viewer
|
||||
- Multiple plates management
|
||||
- Remote control & monitoring
|
||||
- Auto-arrange objects
|
||||
- Auto-orient objects
|
||||
- Hybrid/Tree/Normal support types, Customized support
|
||||
- multi-material printing and rich painting tools
|
||||
- multi-platform (Win/Mac/Linux) support
|
||||
- Global/Object/Part level slicing parameters
|
||||
|
||||
Other major features are:
|
||||
- Advanced cooling logic controlling fan speed and dynamic print speed
|
||||
- Auto brim according to mechanical analysis
|
||||
- Support arc path(G2/G3)
|
||||
- Support STEP format
|
||||
- Assembly & explosion view
|
||||
- Flushing transition-filament into infill/object during filament change
|
||||
|
||||
# How to compile
|
||||
Following platforms are currently supported to compile:
|
||||
- Windows 64-bit, [Compile Guide](https://github.com/bambulab/BambuStudio/wiki/Windows-Compile-Guide)
|
||||
- Mac 64-bit, [Compile Guide](https://github.com/bambulab/BambuStudio/wiki/Mac-Compile-Guide)
|
||||
|
||||
# Report issue
|
||||
You can add an issue to the [github tracker](https://github.com/bambulab/BambuStudio/issues) if **it isn't already present.**
|
||||
|
||||
# License
|
||||
Bambu Studio is licensed under the GNU Affero General Public License, version 3. Bambu Studio is based on PrusaSlicer by PrusaResearch.
|
||||
|
||||
PrusaSlicer is licensed under the GNU Affero General Public License, version 3. PrusaSlicer is owned by Prusa Research. PrusaSlicer is originally based on Slic3r by Alessandro Ranellucci.
|
||||
|
||||
Slic3r is licensed under the GNU Affero General Public License, version 3. Slic3r was created by Alessandro Ranellucci with the help of many other contributors.
|
||||
|
||||
The GNU Affero General Public License, version 3 ensures that if you use any part of this software in any way (even behind a web server), your software must be released under the same license.
|
||||
|
||||
The BambuNetworking and BambuTunnel plugins are based on non-free libraries. They are optional to the Bambu Studio and provides extended functionalities for users.
|
||||
|
||||
- **OrcaSlicer** is licensed under the GNU Affero General Public License, version 3.
|
||||
- The **GNU Affero General Public License**, version 3 ensures that if you use any part of this software in any way (even behind a web server), your software must be released under the same license.
|
||||
- OrcaSlicer includes a **pressure advance calibration pattern test** adapted from Andrew Ellis' generator, which is licensed under GNU General Public License, version 3. Ellis' generator is itself adapted from a generator developed by Sineos for Marlin, which is licensed under GNU General Public License, version 3.
|
||||
- The **Bambu networking plugin** is based on non-free libraries from BambuLab. It is optional to the OrcaSlicer and provides extended functionalities for Bambulab printer users.
|
||||
|
||||
1
Readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
Init Version
|
||||
47
SECURITY.md
@@ -1,47 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
At OrcaSlicer, we are committed to maintaining the security of our ecosystem. Our policy is to ensure that we do not introduce vulnerabilities and that any security issues are addressed promptly and responsibly. We appreciate your help in improving the security of OrcaSlicer and thank you for your responsible disclosure.
|
||||
Reporting Security Bugs
|
||||
|
||||
## To report a security bug, please follow these guidelines:
|
||||
|
||||
* Email Security Bugs:
|
||||
Send an email to the lead maintainer at softfeverever@gmail.com.
|
||||
Include the word "SECURITY" in the subject line of your email.
|
||||
|
||||
* Response Times:
|
||||
The lead maintainer will acknowledge receipt of your email within one week (7 days).
|
||||
A detailed response will follow within 48 hours, outlining the next steps for handling your report.
|
||||
After the initial reply, the security team will keep you informed about the progress toward a fix and any announcements.
|
||||
|
||||
* Information and Collaboration:
|
||||
We may request additional information or guidance as we work on addressing the issue.
|
||||
|
||||
* Handling the Report:
|
||||
OrcaSlicer will confirm the problem and determine the affected versions.
|
||||
We will audit the code to find any similar issues and prepare fixes for all releases still under maintenance.
|
||||
Fixes will be released as quickly as possible.
|
||||
|
||||
* Third-Party Modules:
|
||||
Report security issues in third-party modules to the respective maintainer of those modules.
|
||||
|
||||
## Security Disclosure Guidelines
|
||||
|
||||
When disclosing a vulnerability, please follow these steps to ensure your report is clear and actionable:
|
||||
|
||||
* Provide Detailed Information:
|
||||
Scope: Clearly define the scope of the vulnerability.
|
||||
Potential Impact: Let us know who could be affected by this exploit.
|
||||
Reproduction Steps: Document detailed steps to reproduce the vulnerability.
|
||||
|
||||
Reference OWASP Guidelines:
|
||||
Follow the <a href="https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html">OWASP Vulnerability Disclosure Cheat Sheet</a> for best practices in vulnerability disclosure.
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
To enhance security when using OrcaSlicer, we recommend following these steps:
|
||||
|
||||
* SEE SOMETHING: If you notice anything suspicious or have concerns, please report it.
|
||||
* SAY SOMETHING: If you have any doubts or need assistance, do not hesitate to contact us.
|
||||
|
||||
### Thank you for your commitment to the security of OrcaSlicer. Your efforts help us maintain a safe and reliable ecosystem.
|
||||
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 729 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 353 KiB |
|
Before Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 305 KiB |
|
Before Width: | Height: | Size: 158 KiB |
@@ -1,604 +0,0 @@
|
||||
# Texture Displacement — Technical Notes
|
||||
|
||||
Branch: `feature/texture_displacement`. This document is a knowledge dump of the whole feature as
|
||||
it stands: architecture, file map, algorithms, known bugs found and fixed (with root causes worth
|
||||
remembering), and what's still deferred. Written so a fresh session (or a fresh pair of eyes) can
|
||||
pick this up without re-deriving everything from scratch.
|
||||
|
||||
## What it does
|
||||
|
||||
A paint-style gizmo (`GLGizmoTextureDisplacement`) that lets you:
|
||||
- Paint one or more "layers" onto a model's surface, each a height-map texture with its own
|
||||
depth/tiling/rotation/offset/invert/tile-mode/projection-mode/blend-mode.
|
||||
- Pick a texture from a shipped library (`resources/textures/displacement/`) or import your own
|
||||
(saved into `<data_dir>/textures/displacement/`, kept separate so app updates can't clobber it).
|
||||
- Combine overlapping layers with image-editor-style blend modes (Add/Subtract/Multiply/Divide).
|
||||
- Preview the true displaced result live, before baking (background job, not on the UI thread).
|
||||
- Optionally preview via a fast GPU bump-map shader instead (no real geometry movement, just
|
||||
shading) for a lighter-weight alternative.
|
||||
- Bake into real mesh geometry on demand, restricted to the painted area only.
|
||||
- Subdivide a low-poly model first so there are enough vertices to show fine detail.
|
||||
- Unwrap a painted patch with a real CGAL LSCM parameterization and view it in a dedicated,
|
||||
dockable 2D "UV Editor" pane.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Data model (per `ModelVolume`)
|
||||
|
||||
Each of up to `TEXTURE_DISPLACEMENT_MAX_LAYERS` (8) layers gets its **own independent
|
||||
`FacetsAnnotation`** paint mask — the exact same `TriangleSelector`/`FacetsAnnotation` machinery
|
||||
every other paint gizmo (FdmSupports, Seam, MMU, FuzzySkin) already uses, just one full instance
|
||||
per layer slot instead of one per volume. This is what makes "layered/blended" painting work for
|
||||
free: the same triangle can be `ENFORCER` in layer 2's mask and layer 5's mask simultaneously, and
|
||||
at bake/preview time each layer displaces the surface left by the previous one (image-editor-layer
|
||||
semantics).
|
||||
|
||||
**Important gotcha**: `ModelVolume` does **not** hold `std::array<FacetsAnnotation, 8>`. It holds
|
||||
8 individually-named fields (`texture_displacement_facets_0` .. `_7`) plus a
|
||||
`texture_displacement_facet(int slot)` accessor. Reason: `FacetsAnnotation`'s ctor is private,
|
||||
friended only to `ModelVolume`; `std::array`'s own implicitly-generated special member functions
|
||||
are generated with **`std::array`'s** access rights, not the enclosing class's, so friendship does
|
||||
not propagate through the array wrapper. This is a real MSVC C2280 if you try it — confirmed by
|
||||
attempting it. `TextureDisplacementFacetsData` (a `std::array<TriangleSelector::TriangleSplittingData, 8>`,
|
||||
used to carry paint-mask *data* around, e.g. into the bake job) is fine as a real `std::array`
|
||||
since `TriangleSplittingData` has an ordinary public ctor — only the `FacetsAnnotation` object
|
||||
itself has the friend-ctor problem.
|
||||
|
||||
Plus `std::vector<TextureDisplacementLayer> texture_displacement_layers;` — the plain-data layer
|
||||
definitions (texture bytes + params), ordinary public ctor, safe in a vector.
|
||||
|
||||
Touch points that had to mirror the existing `FacetsAnnotation` pattern (see `supported_facets` for
|
||||
the template): all constructors' asserts, copy ctors' init lists, the `-1`-id deserialization ctor,
|
||||
`set_new_unique_id()`, cereal `save`/`load`, `is_texture_displacement_painted()`, and
|
||||
`reset_extra_facets()` (called whenever a topology-changing op like Simplify or subdivision
|
||||
replaces the mesh — this is what drops any unbaked texture-displacement paint, since there's no
|
||||
remap-across-topology-change support for it yet, see Limitations).
|
||||
|
||||
### Bake algorithm (`libslic3r/TextureDisplacement.cpp`)
|
||||
|
||||
`build_texture_displacement(base_mesh, layers, facets_data)` is **accumulate-then-displace, and
|
||||
topology-preserving**: the returned mesh has exactly the input's vertices and triangles, in the same
|
||||
order — only the positions of displaced vertices differ.
|
||||
|
||||
1. `its_compactify_vertices()` on a copy of the input. In practice a no-op (it only drops
|
||||
*unreferenced* vertices, and preserves the order and indices of the rest). It is there to
|
||||
guarantee the index alignment step 3 depends on.
|
||||
2. Area-weighted vertex normals of the **undisplaced** mesh, computed once. Every layer both
|
||||
projects and displaces along these, so a vertex covered by several layers moves along one single
|
||||
well-defined direction.
|
||||
3. For each layer in slot order: deserialize its stored paint mask into a `TriangleSelector` against
|
||||
the **base mesh** (never against a previous layer's output), then
|
||||
`selector.get_facets_strict(ENFORCER)` → the painted patch. Two facts are exploited:
|
||||
- `get_facets_strict()` returns the mesh's **entire** referenced vertex array regardless of which
|
||||
state was asked for — only `.indices` is filtered by state. So `get_facets_strict(ENFORCER)`
|
||||
and `get_facets_strict(NONE)` share identical vertex indexing, which is what lets boundary
|
||||
detection be a plain index check instead of a position-hash lookup.
|
||||
- The selector's vertex array *starts with* the mesh's own vertices (extra ones created where a
|
||||
brush stroke split a triangle are appended after them), and `get_facets_strict()` emits the
|
||||
referenced ones in order. Combined with step 1, **selector vertex index `i` is our vertex `i`**.
|
||||
Split vertices live past the end of our array and are simply skipped — they sit on the paint
|
||||
boundary anyway (splitting only happens at partial coverage), so they would be pinned regardless.
|
||||
4. A vertex used by at least one **unpainted** triangle is a boundary vertex — pinned, never
|
||||
displaced (its final position is ambiguous, it belongs to both regions). Only vertices used
|
||||
exclusively by painted triangles get displaced. This is what keeps bakes seamless with zero
|
||||
remeshing/hole-filling at the seam.
|
||||
5. Per interior vertex: sample the height texture (`sample_layer_height()`, see Projection methods)
|
||||
and fold `height * depth_mm * (invert ? -1 : 1)` into that vertex's running total via the layer's
|
||||
`TextureBlendMode` (see Blend modes). A `visited` set makes each layer fold in exactly **once**
|
||||
per vertex, no matter how many of the patch's triangles share it — otherwise a Multiply/Subtract
|
||||
layer would apply two or three times over depending on local triangle fan-out.
|
||||
6. Finally, move each touched vertex along its (step 2) normal by its accumulated total.
|
||||
|
||||
**This replaced a sequential design** that re-meshed after each layer and carried the next layer's
|
||||
paint mask onto the result with `TriangleSelector::remap_painting()`. That was the root cause of the
|
||||
reported "the second texture is never applied" bug: remapping a mask onto a mesh whose vertices had
|
||||
just been displaced out from under it routinely produced an empty bitstream, and the layer was then
|
||||
silently `continue`d past. It was also what forced the per-layer vertex duplication and the final
|
||||
`its_compactify_vertices()` weld. The current formulation has neither problem, is substantially
|
||||
faster (no remap, no welding, one pass), makes blend modes possible at all (they need a shared
|
||||
per-vertex accumulator, which sequential re-meshing cannot provide), and — because the output keeps
|
||||
the input's exact vertex indexing — lets GUI code overlay a preview on the base mesh with no index
|
||||
translation.
|
||||
|
||||
### Blend modes
|
||||
|
||||
`TextureBlendMode` {Add, Subtract, Multiply, Divide}, per layer, applied per vertex against the
|
||||
total accumulated by the layers **below** it (lower slots). The quantity blended is a signed
|
||||
displacement in **mm**, not a pixel value.
|
||||
|
||||
Add/Subtract are self-explanatory. Multiply/Divide are *scaling* operations and so need a unit
|
||||
convention: they treat the layer's own value as a **factor relative to 1 mm**. That makes `depth_mm`
|
||||
a gain, and — the property that makes a Multiply layer usable as a mask — a layer with depth 1 mm
|
||||
sampling a white (1.0) texel multiplies by exactly 1, i.e. leaves the layers below unchanged.
|
||||
Divide floors its divisor's magnitude at 0.05 — a black texel samples to *exactly* zero, so the
|
||||
divisor really does hit zero in ordinary use, and an unbounded `1/0` would fling vertices thousands
|
||||
of mm away and poison the mesh's bounding box (and every plate/print-volume check downstream). The
|
||||
floor doubles as a cap on how far Divide can amplify the relief beneath it: at most 20×.
|
||||
|
||||
The **lowest painted layer ignores its blend mode**: it has nothing beneath it, and Multiply/Divide
|
||||
against an implicit zero base would annihilate (or blow up) it. Enforced in `build_texture_
|
||||
displacement()` (the first layer to reach a given vertex always folds in additively) and surfaced in
|
||||
the UI, which labels that layer "Base layer" instead of offering a control that silently does nothing.
|
||||
|
||||
### Projection methods
|
||||
|
||||
Four choices per layer (`TextureProjectionMethod`), all funneling through `apply_uv_transform()`
|
||||
(scale by `1/tiling_scale`, rotate by `rotation_deg`, add `offset`). They are dispatched by
|
||||
`sample_layer_height()`, which returns a **height**, not a UV — because Triplanar takes three
|
||||
texture samples per vertex and so has no single UV that represents it.
|
||||
|
||||
- **Triplanar** (default) — samples the texture on all three world planes (`(y,z)`, `(x,z)`, `(x,y)`)
|
||||
and blends the three by the vertex's own normal raised to `TRIPLANAR_BLEND_SHARPNESS` (4).
|
||||
This is the fix for a real, user-reported bug. The previous version *hard-picked* the single axis
|
||||
most aligned with the normal, which is discontinuous wherever that dominant axis flips: on a +X
|
||||
face the planar coordinate is `(y, z)`, on a −Y face it is `(x, z)`, so at the shared edge `u`
|
||||
jumps from `y_edge` to `x_edge`. On a box centred near the origin those two happen to **agree** at
|
||||
the (+,+) and (−,−) corners and **differ by the full corner width** at the (+,−) and (−,+) corners
|
||||
— which is exactly the "two bad corners, two good ones" symmetry that was observed. A weighted
|
||||
blend is continuous across the transition by construction, since the weight of the axis being left
|
||||
behind falls smoothly to zero. (Note this removes the hard *seam*; some cross-fade blurring in the
|
||||
band right at a 90° edge is inherent to triplanar mapping. A genuinely seam-free wrap around a box
|
||||
needs a real unwrap — that is what the LSCM mode is for.)
|
||||
- **Cylindrical** — wraps around an axis through the patch centroid, axis auto-picked as the world
|
||||
axis *least* aligned with the average normal (perpendicular to the outward radial normal, as a
|
||||
cylinder's own axis would be). `u = angle * local_radius` (arc length in mm), `v = distance along
|
||||
axis`. Approximation, not an exact fit for arbitrary geometry.
|
||||
- **Spherical** — longitude/latitude around the centroid, scaled by local radius. Same caveat.
|
||||
- **LSCM** — real UV unwrap via `MeshBoolean::cgal::parameterize_lscm()` (CGAL's
|
||||
`Surface_mesh_parameterization` package, LSCM algorithm). Computed **once per patch** (not
|
||||
per-vertex like the others — it's a single global least-squares solve), then each vertex looks up
|
||||
its precomputed UV. Requires the patch to be a single topological disk (one connected component,
|
||||
one boundary loop) — `compute_lscm_uvs()` returns empty and the layer silently falls back to
|
||||
Triplanar if not (e.g. multiple disconnected painted islands, or a fully closed patch).
|
||||
CGAL's parameterizer needs a mesh with no isolated/unreferenced vertices, but `get_facets_strict()`
|
||||
returns the *whole* mesh's vertex array — so there's a compaction step
|
||||
(`compact_patch_with_map()`) that builds a clean sub-mesh + an index map back to the original
|
||||
(uncompacted) vertex numbering, purely local to this file.
|
||||
- **ViewProjected** ("From view") — a flat projection along a fixed direction captured from the 3D
|
||||
camera, like a slide projector. `capture_view_projection()` takes the camera's right/up axes,
|
||||
transforms them into the volume's *local* frame (so the projection rides along if the part is later
|
||||
moved), and stores them as `TextureDisplacementLayer::view_project_right/up` (unit vectors, so the
|
||||
projected coordinate stays in mm and `tiling_scale` keeps meaning mm). `sample_layer_height()`
|
||||
projects `Vec2f(dot(pos, right), dot(pos, up))`. Single-valued per point, so — like LSCM but unlike
|
||||
blended Triplanar — the fast preview and UV-check overlay precompute it per vertex
|
||||
(`compute_layer_vertex_uvs()`) and drive the shader's `use_vertex_uv` path. Faces angled away from
|
||||
the projector smear; that is inherent to view projection, not a bug.
|
||||
|
||||
### Manual seams and island cutting
|
||||
|
||||
`TextureDisplacementLayer::lscm_seam_edges` — undirected mesh-vertex-index edge pairs the unwrap is
|
||||
forced to cut along, on top of the dihedral-angle seams. `segment_into_charts()` takes a set of these
|
||||
(translated from mesh → compacted-patch numbering inside `compute_patch_unwrap()`) and refuses to
|
||||
union two triangles across a marked edge whatever their angle. Both the unwrap cache key and the
|
||||
gizmo's `UVEditorState` include the seam list, so marking a seam (which leaves the paint mask
|
||||
untouched) still forces a re-solve. Like the paint masks, seams are mesh-index-space and so dropped on
|
||||
any topology change.
|
||||
|
||||
Two ways to write to it:
|
||||
- **Mark seam (manual, #9)** — a "Mark seams" click mode (`m_seam_edit_mode`) that suppresses
|
||||
painting. A click raycasts the volume (`m_c->raycaster()->raycasters()[idx]->unproject_on_mesh()`,
|
||||
`idx` = the volume's slot among model-part volumes), finds the facet's edge nearest the hit point,
|
||||
and toggles it. Marked edges render as a red overlay (`render_seam_overlay()`), pulled toward the
|
||||
camera so they read on top. This is the Blender mark-seam workflow.
|
||||
- **Cut island (auto, #17)** — `cut_island()` takes the selected chart's triangles (back-mapped from
|
||||
the unwrap via `source_vertex`), finds their 3D bounding box, and marks every edge that straddles
|
||||
the mid-plane perpendicular to the longest axis. The re-unwrap then splits the chart across its
|
||||
narrow waist — the "islands might be very long" case. Exposed as the UV pane's **Cut** button.
|
||||
|
||||
### UV-check overlays (checker / distortion)
|
||||
|
||||
`resources/shaders/{110,140}/texture_displacement_uvcheck.{vs,fs}`, one shader with a `mode` uniform,
|
||||
drawn over the painted patch (`rebuild_uvcheck_mesh()`/`render_uvcheck_mesh()`, P3N3T2: `normal.x` =
|
||||
distortion, `tex_coord` = uv), pulled forward with a polygon offset. **Checker** (#13) samples a
|
||||
procedural checkerboard at the layer's uv (per-vertex for LSCM/ViewProjected, in-shader triplanar
|
||||
otherwise) — squares that stay square mean low distortion. **Distortion** (#14) colours each triangle
|
||||
blue→green→red by `log2(uv_area / surface_area)` centred on the patch's *median* stretch (so a
|
||||
globally-scaled unwrap reads as uniformly ideal and only relative stretch shows), averaged to
|
||||
vertices. A separate **Show mesh wireframe** toggle (#8) draws the whole volume's triangle edges,
|
||||
rebuilt only when the vertex count changes (not per stroke).
|
||||
|
||||
### Tiling
|
||||
|
||||
`DecodedHeightTexture::sample(uv, tile_enabled, tile_method)`. Two tile methods when enabled
|
||||
(Repeat, MirroredRepeat). **When `tile_enabled` is false, sampling outside `[0,1)` returns `0`
|
||||
directly** — clamping the *coordinate* into range (what an earlier version did) instead smears the
|
||||
border row/column of pixels outward to infinity in every direction, which is a real bug that was
|
||||
reported and fixed (visually: streaky lines radiating out from the painted patch).
|
||||
|
||||
### Subdivision (`subdivide_mesh_uniform()`)
|
||||
|
||||
Deliberately **whole-mesh and uniform**, not limited to the painted patch. A patch-only /
|
||||
adaptive subdivision would create a classic T-junction/cracking problem where the denser
|
||||
(subdivided) and sparser (untouched) regions meet — the fine side has edge midpoints the coarse
|
||||
side doesn't know about, producing a real (non-manifold-looking) crack in the baked geometry. This
|
||||
was consciously scoped down from the original plan's "adaptive per-patch subdivider" idea to avoid
|
||||
that correctness risk (a subtly-cracked mesh is a much worse outcome than "not implemented yet").
|
||||
Algorithm: recursive 1-to-4 triangle split via edge midpoints, with a shared per-pass midpoint cache
|
||||
(keyed by sorted vertex-index pair) so triangles sharing an edge get the *same* new vertex — capped
|
||||
at `max_iterations` (default 6) passes to bound worst-case triangle-count explosion.
|
||||
|
||||
Wired as a "Subdivide model" button in the gizmo panel — a real, committed geometry change (like
|
||||
Bake), using the same `save_painting()`/`set_mesh()`/`restore_painting()` dance `GLGizmoSimplify`
|
||||
uses: supported/seam/mmu/fuzzy-skin masks get remapped onto the new triangles, texture-displacement
|
||||
paint does not (no remap support yet) and is dropped rather than left pointing at now-meaningless
|
||||
triangle indices.
|
||||
|
||||
### Preview pipeline (perf)
|
||||
|
||||
`rebuild_preview()` used to call `build_texture_displacement()` **synchronously on the UI thread**
|
||||
on every stroke-end and every slider release. With multiple painted layers this got slow (each
|
||||
layer's PNG sampling + vertex welding + `remap_painting()` stacks up). Fixed by moving the actual
|
||||
computation into `TextureDisplacementPreviewJob` (mirrors `TextureDisplacementBakeJob`'s
|
||||
process()/finalize() split), queued on the app's shared UI job worker via plain `queue_job()` (not
|
||||
`replace_job()` — that worker is shared app-wide, including with Bake; `replace_job()` would cancel
|
||||
an in-flight bake if one happened to be running). A `m_preview_generation` counter discards stale
|
||||
results if a burst of edits queues several jobs in a row and an older one finishes after a newer one.
|
||||
|
||||
Two other real perf fixes worth remembering:
|
||||
- Sliders in ImGui report "changed" continuously on every drag frame, not just once on release —
|
||||
gating the (then-synchronous) rebuild behind "mouse button not currently down" was necessary to
|
||||
stop dozens of rebuilds per drag.
|
||||
- `decode_height_texture()` used to re-decode the same PNG from scratch on every call. Now cached
|
||||
in `TextureDisplacement.cpp`, keyed by a `weak_ptr` to the layer's `image_data` (not just the raw
|
||||
pointer — a `weak_ptr` correctly detects a freed-then-reused address, where a raw-pointer key
|
||||
would alias a stale cache entry onto an unrelated later texture).
|
||||
|
||||
### Fast bump preview (GPU-only, no CPU meshing)
|
||||
|
||||
`resources/shaders/{110,140}/texture_displacement_bump.{vs,fs}`, registered as
|
||||
`"texture_displacement_bump"`. Perturbs the *shading* normal from the height texture's local
|
||||
gradient instead of moving geometry — active-layer-only, toggled via a "Fast preview (normal map)"
|
||||
checkbox. Vertex format is `GLModel::Geometry::EVertexLayout::P3N3T2`: `normal.x` carries the
|
||||
per-vertex paint weight (0/1) and `tex_coord` carries a precomputed texture UV, so it can use
|
||||
`GLModel` normally instead of needing a hand-rolled VBO/VAO manager. Weight buffer is
|
||||
rebuilt at the same cadence as the true-displacement preview (stroke-end/slider-release), using the
|
||||
**live** `TriangleSelector` state (not the flushed model facets), so it doesn't lag by a full model
|
||||
round-trip.
|
||||
|
||||
The perturbed normal is the analytic one for a height field `H = ±depth_mm · h(uv)` displaced along
|
||||
`N` over any orthonormal surface tangent pair `T`/`B`:
|
||||
|
||||
N' = normalize(N − (dH/da)·T − (dH/db)·B), a = dot(p,T), b = dot(p,B)
|
||||
|
||||
The two slopes have to be genuine **mm-per-mm** derivatives for the preview's apparent depth to
|
||||
match the bake's — see bug #13.
|
||||
|
||||
**Two projection paths (`use_vertex_uv` uniform):**
|
||||
- **Triplanar (`use_vertex_uv = 0`)** — `uv` and the `T`/`B` axes are both derived in-shader from
|
||||
the dominant normal component, mirroring `project_planar()`/`apply_uv_transform()`, and the slope is
|
||||
formed analytically. `T`/`B` are the projection's axis-aligned pair, exact only when the face is
|
||||
axis-aligned; the shader drops the along-normal component to keep the gradient in the surface. Here
|
||||
one `uv` unit is exactly `tiling_scale` mm, so the `1/tiling_scale` gradient factor is right.
|
||||
- **Precomputed UV (`use_vertex_uv = 1`, used for LSCM)** — `uv` comes per-vertex from the CPU
|
||||
(`compute_lscm_uvs(patch, layer)`, so island placement + tiling/rotation/offset are already folded
|
||||
in), and the perturbed normal is built with **Mikkelsen's method** ("Bump Mapping Unparametrized
|
||||
Surfaces on the GPU"): the surface gradient taken directly from the screen-space derivatives of the
|
||||
*sampled height* and position. **This makes no uv→mm scale assumption**, which is essential —
|
||||
the first cut used the same global `1/tiling_scale` factor as triplanar and the depth came out
|
||||
visibly wrong, because an LSCM map is **conformal, not isometric**: it is globally area-scaled but
|
||||
the *local* mm-per-uv varies across the chart. `dFdx(h)` captures the true on-screen rate of change
|
||||
however the chart is stretched. **This path is also what makes the fast preview follow the UV
|
||||
editor: move an island and its uv — hence its bump — moves with it** (the bump mesh rebuilds on
|
||||
drag-end, since `on_island_edited(finished)` → `rebuild_preview()` → `rebuild_bump_preview_mesh()`).
|
||||
The branch is uniform (`use_vertex_uv` is a uniform) and the paint weight gates by multiply, so the
|
||||
texture derivatives stay well defined. A triangle straddling a seam has a discontinuous uv → the
|
||||
`det≈0` guard skips it (a localised preview-only artifact, never in the bake).
|
||||
|
||||
Remaining deliberate approximation: the GPU sampler's wrap mode stands in for
|
||||
`tile_enabled`/`tile_method`, so with tiling *off* the GPU repeats where the CPU returns 0 outside
|
||||
`[0,1)`.
|
||||
|
||||
> **Known divergence from the CPU path (not yet reconciled).** The shader's `project_uv()` mirrors
|
||||
> the *hard-axis* `project_planar()`, but the CPU's Triplanar mode is now a **blended** three-plane
|
||||
> sample (see Projection methods — that change is what fixed the 90°-corner seam). The two therefore
|
||||
> still agree on any face that is roughly axis-aligned (one blend weight ≈ 1 there, so the blend
|
||||
> degenerates to exactly the hard-axis pick), and disagree in the cross-fade band around a sharp
|
||||
> edge — precisely where the fast preview will still show the old hard seam that the true preview and
|
||||
> the bake no longer have. Reconciling it means sampling all three planes in the shader and blending
|
||||
> the three gradients by `pow(abs(N), TRIPLANAR_BLEND_SHARPNESS)`, the same weights
|
||||
> `sample_layer_height()` uses. Also note the shader is still **active-layer-only** and knows nothing
|
||||
> about `TextureBlendMode`, so a multi-layer stack cannot match the true preview by construction.
|
||||
|
||||
### On-canvas "Adjust Texture" gizmo
|
||||
|
||||
A per-active-layer toggle ("Adjust placement (drag on model)") that disables painting and shows a
|
||||
flat pan panel (free 2D drag on both axes) plus two arrows along the patch's own U/V axes
|
||||
(constrained single-axis drag). Anchored to the painted patch's centroid/average-normal
|
||||
(`compute_layer_paint_anchor()`). Hit-testing is screen-space distance/point-to-segment (not real
|
||||
3D ray intersection against the handle geometry) — simple and good enough at this handle size.
|
||||
|
||||
Known unverified detail: the **offset-drag direction/sign** is reasoning-based (increasing `offset`
|
||||
shifts which texel is sampled at a fixed world position, which visually slides the pattern the
|
||||
*opposite* way — so the code subtracts), not visually confirmed, since this environment can't
|
||||
render pixels. May need a one-line sign flip once actually tested. The rotation-arrow-implied
|
||||
direction should be reliable (it follows directly from a self-consistent 2D basis, no such
|
||||
ambiguity).
|
||||
|
||||
### UV Editor pane
|
||||
|
||||
`UVEditorCanvas` (`src/slic3r/GUI/UVEditorCanvas.hpp/.cpp`) — a standalone `wxGLCanvas` rendering the
|
||||
flattened LSCM islands (per-island wireframe + outline + fill) over the height texture (background
|
||||
quad tiled across the whole unwrap), with mouse pan/zoom. It is wrapped in a **`UVEditorPanel`**
|
||||
(same file) that adds a button row (Frame / Snap / Average scale) and a Blender-style status line
|
||||
along the bottom naming the current gesture and the shortcuts in play. The *panel* is what is
|
||||
registered as a `wxAuiPaneInfo` pane on `Plater`'s `m_aui_mgr`; `Plater::show_uv_editor(bool)`
|
||||
shows/hides it (deferred via `CallAfter`, since the gizmo calls it mid-3D-frame), and
|
||||
`get_uv_editor_canvas()` returns the inner canvas the gizmo talks to.
|
||||
|
||||
Deliberately **shares the app's one real `wxGLContext`** (`wxGetApp().init_glcontext(*this)`, the
|
||||
same call `View3D`/`Preview`/`AssembleView` make) rather than creating an independent context like
|
||||
`SkipPartCanvas` does elsewhere in this codebase — this is what lets it reuse the already-registered
|
||||
`"flat"`/`"flat_texture"` shaders and `GLModel` as-is, instead of needing its own shader
|
||||
compilation/VBO management.
|
||||
|
||||
**Geometry is uploaded once, in the unwrap's own (raw, mm) coordinates**, one `GLModel` set per
|
||||
island; each island is then drawn through its own 2x3 affine (`island_transform_matrix()` composed
|
||||
with the layer's tiling/rotation/offset) passed as the `flat` shader's `view_model_matrix`. This is
|
||||
the fix for the ~200 ms-per-frame island-drag stall (#3): the old design pre-transformed every UV on
|
||||
the CPU and re-uploaded the entire wireframe on every mouse-move event, which on a million-triangle
|
||||
patch is exactly as slow as it sounds. Now a drag updates one matrix per island and touches no vertex
|
||||
buffer — `on_island_edited(!finished)` calls only `set_island_transforms()`, and the full
|
||||
`set_islands()` rebuild happens solely when the unwrap itself changes (`unwrap_changed` in
|
||||
`update_uv_editor()`).
|
||||
|
||||
**Gestures** (canvas-owned, reported to the gizmo as incremental deltas via `IslandEditFn`): left-drag
|
||||
= move, right-drag or **R** = rotate (hold **Shift** to snap to 15° steps — quantised on the
|
||||
*cumulative* rotation, not each delta, so it doesn't judder, and accumulated incrementally so it
|
||||
survives crossing ±180°), **S** = scale (R/S modal, click/Enter to confirm, Esc to cancel), wheel =
|
||||
zoom about the cursor, middle-drag = pan, **Home**/**F** = frame all. Scale writes
|
||||
`TextureIsland::scale`; "Average scale" (`average_island_scales()`) sets every island to the mean, so
|
||||
one island scaled by hand can be matched back to its neighbours' texel density. **Snap** (canvas-owned
|
||||
`m_snap_enabled`, toggled from the toolbar) sticks a dragged island's nearest boundary vertex onto a
|
||||
neighbouring island's at drag-*end* only — a magnet that re-applies mid-drag is very hard to pull out
|
||||
of. Toolbar commands the canvas can't service itself (Average scale) are forwarded to the gizmo via
|
||||
`CommandFn`; view-only ones (Frame, Snap) it handles directly.
|
||||
|
||||
## Bugs found and fixed this session (worth remembering)
|
||||
|
||||
These were all real, confirmed root causes (found by reading the actual code path, not guessed):
|
||||
|
||||
1. **Cross-face projection distortion** — see "Triplanar" above. Fixed by projecting each vertex
|
||||
with its own normal instead of one shared patch-average normal.
|
||||
2. **Disabled-tile smearing to infinity** — clamping the UV *coordinate* into `[0,1]` instead of
|
||||
returning 0 outside it, when tiling is off. Fixed in `DecodedHeightTexture::sample()`.
|
||||
3. **Invisible checkbox/radio "checked" state in light mode** — `ImGuiWrapper::push_toolbar_style()`
|
||||
sets `ImGuiCol_CheckMark` to white while the checkbox/radio frame background is fully transparent
|
||||
(alpha 0) over a light window background — a white checkmark on an effectively-white background
|
||||
is invisible by construction. This is a **pre-existing, general app-wide bug**, not specific to
|
||||
this feature (every panel using `push_toolbar_style()` in light mode has it) — fixed by changing
|
||||
just the light-mode branch's `CheckMark` color to the app's teal accent.
|
||||
4. **Distorted (non-aspect-correct) texture thumbnails** — was forcing a square `ImGui::Image` size
|
||||
regardless of the source image's actual aspect ratio.
|
||||
5. **`std::array<FacetsAnnotation, 8>` compile error** — see Data model above (MSVC C2280,
|
||||
`std::array`'s implicit special members don't inherit element-type friendship).
|
||||
6. **Eigen ternary expression-template type mismatch** (MSVC C2446) — `cond ? (n / len) :
|
||||
Vec3f::UnitZ()` fails because the two branches are different unevaluated Eigen expression
|
||||
*types* with no common type; fixed by wrapping the non-`UnitZ()` branch in an explicit
|
||||
`Vec3f(...)` to force a concrete common type.
|
||||
7. **Post-bake stale preview** — `GLGizmoPainterBase::data_changed()`'s change-detection only
|
||||
checks object id / volume count, neither of which changes when Bake replaces a volume's mesh
|
||||
(same object, same volume count, just a new mesh/id on the volume itself) — so the gizmo kept
|
||||
rendering/painting against the pre-bake `TriangleSelectorPatch` until manually deselected and
|
||||
reselected. Fixed by explicitly calling `update_from_model_object()` in the bake-completion
|
||||
callback.
|
||||
8. **Bake job / crash-report `resources` junction going stale** — unrelated to this feature's code,
|
||||
but hit during testing: `build/src/Release/resources` was a leftover **empty plain directory**
|
||||
instead of the junction CMake's post-build step creates (`if not exist` skipped it because the
|
||||
empty folder already "existed"), so the built exe couldn't find `resources/data/hints.ini`,
|
||||
leaving `HintDatabase`'s hint list empty → `rand() % 0` divide-by-zero crash before the UI ever
|
||||
opened. Fixed by deleting the empty folder and manually recreating the `mklink /J` junction.
|
||||
9. **Fast bump preview showing a solid black object** — `GLModel::render()` **unconditionally**
|
||||
re-sets the shader's `"uniform_color"` uniform from its own internal `Geometry::color` field
|
||||
(defaulting to `ColorRGBA::BLACK()`) right before every draw call — so a manual
|
||||
`shader->set_uniform("uniform_color", ...)` call made just before `.render()` gets silently
|
||||
clobbered. Any `GLModel` that needs a specific flat color **must** call `.set_color(...)` on the
|
||||
model itself, not set the shader uniform directly. Found by reading `GLModel::render()`'s actual
|
||||
source rather than guessing at shader/lighting math.
|
||||
10. **UV editor canvas rendering nothing / showing stale content on resize** — the canvas requested
|
||||
a generic `wxGLAttributes().Defaults()` pixel format while sharing the app's one real
|
||||
`wxGLContext` (which was originally created against `View3D`'s canvas, itself requesting a
|
||||
specific RGBA/24-bit-depth/8-bit-stencil format). `wxGLCanvas::SetCurrent()` on WGL/GLX
|
||||
generally requires the target window's pixel format to be compatible with the one the context
|
||||
was created against; a mismatch can make `SetCurrent()` silently fail, leaving the canvas
|
||||
showing whatever was last in its backbuffer (looks exactly like "blank" or "stale image on
|
||||
resize"). Fixed by requesting the same explicit attribute list
|
||||
`OpenGLManager::create_wxglcanvas()` uses for the main view canvases — but see bug #14: the
|
||||
first attempt at this copied only *part* of that list and the symptom therefore survived.
|
||||
11. **`<glad/gl.h>` / `<wx/glcanvas.h>` include-order conflict** — `wx/glcanvas.h` pulls in the
|
||||
platform's real `GL/gl.h`; if that happens before `<glad/gl.h>` is processed in the same
|
||||
translation unit, glad's own header errors out (`OpenGL (gl.h) header already included`).
|
||||
Fixed by including `<glad/gl.h>` first in `UVEditorCanvas.hpp`, before `<wx/glcanvas.h>` — any
|
||||
file that includes this header (including `Plater.cpp`, transitively) needs glad to win that
|
||||
race.
|
||||
12. **Fast preview hidden behind the paint-highlight overlay** — `render_painter_gizmo()` always
|
||||
drew the selection-highlight overlay on top with a depth-bias trick (`glPolygonOffset`) that
|
||||
only makes sense for the *true*-displacement preview: real geometry moves in the painted area,
|
||||
so the depth-biased overlay only wins the depth test in the *unpainted* (coincident) region.
|
||||
The bump preview never moves geometry — its depth is identical to the overlay's *everywhere* —
|
||||
so the overlay was winning the depth test across the whole surface and hiding the bump shading
|
||||
entirely. Fixed by skipping the overlay draw entirely when the bump-preview path is active.
|
||||
13. **Fast preview's apparent depth not matching the true preview's** — the bump shader built its
|
||||
perturbed normal as `normalize(N + depth_mm * vec3(hL-hR, hD-hU, 0))`. Two things wrong with
|
||||
that. (a) `hL-hR` is a height difference across *one texel step*, i.e. `dh/du` already scaled by
|
||||
`2·texel`, and `du` is in uv units, not mm — the real surface slope needs the full chain rule
|
||||
back through `uv = R(rotation) · planar_mm / tiling_scale`, i.e. a further `1/tiling_scale` and
|
||||
a rotation of the gradient by `−rotation`. The missing `1/(2·texel·tiling_scale)` factor is
|
||||
~26× at a 1024px texture and a 20mm tile size, all in the flattening direction — which is
|
||||
exactly what "fast preview has a different height from the real preview" looks like. (b) the
|
||||
gradient was added to model-space `xy`, but the two axes the planar projection actually runs
|
||||
along are `yz`/`xz`/`xy` depending on the dominant normal component, so on any face not
|
||||
dominated by `z` the perturbation was applied to the wrong axes. Fixed by computing the real
|
||||
mm-per-mm slope and rotating it into the projection's own `T`/`B` axes (see "Fast bump preview"
|
||||
above for the derivation).
|
||||
14. **UV editor pane still blank after bug #10** — three separate causes, all of them live at once:
|
||||
- The bug-#10 fix copied `OpenGLManager::create_wxglcanvas()`'s attribute list but **dropped its
|
||||
multisampling attributes** (`WX_GL_SAMPLE_BUFFERS`/`WX_GL_SAMPLES`, 4 samples by default), on
|
||||
the reasoning that a flat 2D wireframe view doesn't need AA. But a differing sample count *is*
|
||||
a differing pixel format, so this left exactly the `wglMakeCurrent()` mismatch bug #10 set out
|
||||
to fix. It now mirrors the full list, AA included, reading `OpenGLManager::can_multisample()`
|
||||
(already resolved by then — `View3D` is constructed first).
|
||||
- `set_mesh()`/`set_background_texture()` each called `render()` **inline**, and both are reached
|
||||
from `update_uv_editor()` → `rebuild_preview()` → the gizmo's ImGui panel — i.e. from the
|
||||
middle of the *3D* canvas's GL frame, and (since `show_uv_editor(true)` is the last line of
|
||||
`update_uv_editor()`) while this pane was still **hidden**. `wxGLCanvas::SetCurrent()` returns
|
||||
false outright on a canvas that isn't shown on screen, and the old code ignored the return
|
||||
value — so every GL call in `render()`, `glViewport`/`glClear` included, silently landed on the
|
||||
3D canvas instead. These now only mark dirty + `Refresh()`; `render()` bails unless
|
||||
`IsShownOnScreen()` *and* `SetCurrent()` succeeds; and `Plater::show_uv_editor()` defers its
|
||||
AUI relayout via `CallAfter` so the pane's first size/paint can't be delivered mid-frame either.
|
||||
- Even once drawing, nothing would have been *visible*: the background quad spanned `[-1,1]²`
|
||||
while LSCM UVs land around `[0,1]²`, and the view was centered on the origin at a half-extent
|
||||
of 0.6. The quad is now the unit square in the same UV space the wireframe uses (which is also
|
||||
where `sample()` maps the texture, regardless of its pixel aspect), the projection's Y is
|
||||
negated so `v` runs down-screen (putting the texture's first pixel row at the top rather than
|
||||
upside down), and the view auto-fits to the unwrap ∪ unit square the first time a patch shows up.
|
||||
15. **A second texture layer was silently never applied** — the reported "multiple textures don't
|
||||
work reliably". Root cause was the old sequential bake: layer N's paint mask was stored against
|
||||
the volume's original mesh, so before layer N+1 could be deserialized the mask had to be carried
|
||||
onto the mesh layer N had *just displaced*, via `TriangleSelector::remap_painting()`. Remapping a
|
||||
mask onto geometry that has moved out from under it routinely returned an empty bitstream, and
|
||||
the code then did `if (data.bitstream.empty()) continue;` — i.e. dropped the layer **without any
|
||||
diagnostic**. Fixed structurally rather than patched: every layer is now evaluated against the
|
||||
base mesh and merged per vertex (see Bake algorithm), so no remap happens at all. Covered by a
|
||||
regression test.
|
||||
16. **Hard-axis triplanar seam at exactly two of a box's four vertical corners** — see "Triplanar"
|
||||
under Projection methods. Worth recording the *diagnostic* here, because the asymmetry is what
|
||||
pinned it down: the user reported the seam at the (X+,Y−) and (X−,Y+) corners with the other two
|
||||
clean. That is precisely what a dominant-axis switch predicts (`u = y` on an X face, `u = x` on a
|
||||
Y face; those agree where `x == y` and differ by the corner width where `x == −y`) and it ruled
|
||||
out every "the texture is wrong" hypothesis, since the texture itself is fine — the *mapping* is
|
||||
discontinuous. Fixed by blending the three axis projections instead of picking one.
|
||||
17. **Use-after-free when removing a texture layer** (latent, pre-existing — found while touching the
|
||||
panel, not caused by it). The layer list's "Remove" button called `remove_texture_layer()` *in
|
||||
the middle of rendering that layer's row*. That erases the layer from
|
||||
`mv->texture_displacement_layers`, shifting every later element down — after which the loop
|
||||
happily carried on dereferencing `layer` for the rest of the row's widgets (depth/tiling sliders,
|
||||
`PopID`) and kept iterating `ordered`, a vector of pointers into the storage that had just moved.
|
||||
Never crashed loudly because `vector::erase` doesn't reallocate, so the reads landed on a *valid*
|
||||
but *wrong* (shifted) layer. Fixed by recording the slot and doing the removal after the loop.
|
||||
18. **Every LSCM island collapsed to a point** (the UV editor was empty; the Tile-size slider did
|
||||
nothing; an LSCM bake came out as a flat "single-face extrude"). One line in
|
||||
`compute_patch_unwrap()`: `chart.indices = std::move(chart_mesh.indices);` ran *before*
|
||||
`area_3d(chart_mesh)` was taken. `area_3d()` iterates those indices, so on the moved-from
|
||||
(emptied) mesh it returned `0`, giving `scale = sqrt(0 / uv_area) = 0` — **every chart's UVs
|
||||
multiplied by zero**. That one zero explained all three symptoms at once (no island extent to
|
||||
draw; a zero-size unwrap is still zero after any tiling divide; the bake sampled ~one constant
|
||||
texel per chart). Fixed by measuring the 3D area before the move. Found only by instrumenting the
|
||||
actual island bbox into the panel — three rounds of reasoning from screenshots had each guessed
|
||||
wrong, because a collapsed-to-a-point unwrap and an off-screen-framed one look identical.
|
||||
|
||||
## Known limitations / deferred work
|
||||
|
||||
- **No `.3mf` serialization** for texture-displacement paint data or texture assets. A background
|
||||
agent attempted this in an earlier session, hit its own usage limit mid-edit, and left
|
||||
`bbs_3mf.cpp` with an undefined forward-declared function; that partial edit was reverted rather
|
||||
than shipped broken. Practical impact: **baked** geometry round-trips fine (it's just an ordinary
|
||||
part of the mesh via the existing mesh serialization path) — what does *not* survive a project
|
||||
save/reload is any *unbaked* paint stroke and texture layer definition.
|
||||
- **No remap-across-topology-change** for texture-displacement paint (`ModelObject::split()`, mesh
|
||||
boolean ops, Simplify, and now `subdivide_mesh_uniform()` all drop it via `reset_extra_facets()`).
|
||||
The other four paint channels (supported/seam/mmu/fuzzy) do get remapped in these cases.
|
||||
- **Cylindrical/Spherical axis/center are auto-picked heuristically**, not user-controllable — no
|
||||
UI to override the auto-detected wrap axis if it picks the "wrong" one for an odd shape.
|
||||
- **Fast preview covers the active layer only**, while the true preview stacks every painted layer —
|
||||
so with more than one layer painted the two will legitimately not agree, independently of bug #13.
|
||||
- **Bump preview and true preview both only refresh at stroke-end**, not continuously during an
|
||||
active drag (a deliberate scope cut for simplicity/consistency — the original plan's "instant
|
||||
update mid-stroke" idea for the bump shader specifically was not carried through).
|
||||
- **On-canvas Adjust-Texture gizmo's offset-drag direction is unverified** (see above).
|
||||
- **The bump shader still uses hard-axis, single-layer projection** while the CPU path is now
|
||||
blended-triplanar and blend-mode aware — see the callout under "Fast bump preview".
|
||||
- **Displacement resolution is capped by the mesh's own vertex density.** Baking only ever *moves*
|
||||
existing vertices (it never inserts any), so a coarse patch cannot show fine texture detail no
|
||||
matter how high-resolution the height map is — that is what the "Subdivide model" button is for.
|
||||
Since the rewrite the bake is topology-preserving, so this is now a hard, explicit property rather
|
||||
than something partly papered over by the old per-layer re-meshing.
|
||||
- **Placeholder toolbar icon** — reuses `toolbar_fuzzy_skin_paint.svg`, noted as a TODO in code.
|
||||
- **Textures are matched to the picker by absolute path** (`TextureDisplacementLayer::path`), so the
|
||||
picker's "which entry is selected" highlight goes blank if a project is moved between machines.
|
||||
Harmless — the layer keeps its own embedded `image_data` and still bakes correctly.
|
||||
|
||||
### Requested UV-editing features — status
|
||||
|
||||
A user working through the feature end-to-end asked for a batch of UV-editing features. All of the
|
||||
functional ones are now implemented (see the sections above): checker (#13), distortion heatmap
|
||||
(#14), mesh wireframe overlay (#8), cut island (#17), project-from-view (#6), and Blender-style mark
|
||||
seam (#9), plus per-island fills, the fast preview honouring the LSCM unwrap and island moves (#1),
|
||||
the UV pane toolbar + status line (#18), Shift-snap rotation, midlevel/bidirectional displacement
|
||||
(#19), and island scale/average/padding/snap (#15/#16/#2).
|
||||
|
||||
Remaining cosmetic / known gaps:
|
||||
- The UV pane toolbar has **text buttons, not icons** — no existing SVG reads cleanly as "average
|
||||
island scale" / "snap islands", so real icons are deferred rather than mis-assigned.
|
||||
- **Mark-seam edge picking** snaps to the nearest edge of the *hit facet* only; it does not
|
||||
highlight the candidate edge on hover before you click (a hover-preview would be a nice refinement).
|
||||
- **Cut island** always halves along the longest 3D axis; there is no UI to pick the cut line.
|
||||
|
||||
## File map
|
||||
|
||||
**libslic3r (core, no GUI dependency):**
|
||||
- `src/libslic3r/TextureDisplacement.hpp/.cpp` — data model, bake algorithm, projection methods,
|
||||
tiling, subdivision. See doc comments throughout, they're kept accurate and up to date.
|
||||
- `src/libslic3r/MeshBoolean.hpp/.cpp` — added `parameterize_lscm()` in the `cgal` sub-namespace,
|
||||
reusing the existing `CGALMesh`/`_EpicMesh`/conversion-helper infrastructure already there for
|
||||
mesh boolean ops. New CGAL includes: `Polygon_mesh_processing/border.h`,
|
||||
`Polygon_mesh_processing/connected_components.h`, `Surface_mesh_parameterization/{Error_code,
|
||||
LSCM_parameterizer_3, parameterize}.h`. No new dependency — CGAL 5.6.3 is already vendored and
|
||||
the `Surface_mesh_parameterization` package headers were already present, just unused before now.
|
||||
- `src/libslic3r/Model.hpp/.cpp` — the 8 named `FacetsAnnotation` fields + accessor,
|
||||
`texture_displacement_layers`, and all the mirrored touch points (see Data model above).
|
||||
|
||||
**GUI:**
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp/.cpp` — the gizmo. Panel controls: dock/
|
||||
undock toggle, brush/face/connected-area selection mode + "select whole model" button, per-layer
|
||||
texture picker + depth/tiling/rotation/invert/tile-mode/projection-mode/blend-mode controls,
|
||||
"Adjust placement" toggle (on-canvas gizmo), "Fast preview (normal map)" toggle, "Subdivide model"
|
||||
button, Add layer/Erase all/Bake.
|
||||
- `src/slic3r/GUI/TextureLibrary.hpp/.cpp` — scans the shipped + user texture folders, imports an
|
||||
arbitrary image into the user folder (converting it to the 8-bit grayscale PNG libslic3r decodes),
|
||||
and loads a library file's bytes for a layer. The image→grayscale-PNG conversion lives here, on the
|
||||
GUI side, because libslic3r has no image toolkit; both the import path and the "pick a shipped
|
||||
texture" path go through the same one function.
|
||||
- `resources/textures/displacement/*.png` — the 10 shipped height maps (Bricks, Grid, Hexagons,
|
||||
Knurl, Noise, Quilt, Studs, Waves, Weave, Wood Grain). All 512×512 8-bit grayscale and **seamless**
|
||||
(each is periodic over the full image in both axes, so tiling shows no seam). Generated
|
||||
procedurally; the whole `resources/` tree is installed recursively by CMake, so a new folder under
|
||||
it ships with no build-system change.
|
||||
- `src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.hpp/.cpp` — background bake commit.
|
||||
- `src/slic3r/GUI/Jobs/TextureDisplacementPreviewJob.hpp/.cpp` — background preview compute
|
||||
(mirrors the bake job's shape but commits nothing to the Model).
|
||||
- `src/slic3r/GUI/UVEditorCanvas.hpp/.cpp` — the 2D UV unwrap viewer widget.
|
||||
- `src/slic3r/GUI/Plater.hpp/.cpp` — `uv_editor_canvas` member, AUI pane registration,
|
||||
`get_uv_editor_canvas()`/`show_uv_editor()`.
|
||||
- `src/slic3r/GUI/GLShadersManager.cpp` — registers `"texture_displacement_bump"`.
|
||||
- `resources/shaders/{110,140}/texture_displacement_bump.{vs,fs}` — the bump-preview shader.
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp` — `PainterGizmoType::TEXTURE_DISPLACEMENT`.
|
||||
- `src/slic3r/GUI/Gizmos/GLGizmosManager.hpp/.cpp` — `EType::TextureDisplacement` registration.
|
||||
- `src/slic3r/GUI/ImGuiWrapper.cpp` — the light-mode checkmark-color fix (bug #3 above; a
|
||||
pre-existing, general bug, not scoped to this feature).
|
||||
|
||||
**CMake:** all new source files added to `src/libslic3r/CMakeLists.txt`,
|
||||
`src/slic3r/CMakeLists.txt` (in roughly-alphabetical position matching each list's existing
|
||||
convention), and `tests/libslic3r/CMakeLists.txt` for the unit test file.
|
||||
|
||||
**Tests:** `tests/libslic3r/test_texture_displacement.cpp` — **run and passing** (7 cases, 116
|
||||
assertions). Covers `decode_height_texture` round-trip, empty-layer no-op, full-cube uniform
|
||||
displacement, boundary-vertex pinning on a hand-built fan mesh, and — added with the bake rewrite —
|
||||
a regression test that a **second layer over the same area actually contributes** (the bug that
|
||||
rewrite fixed), a table-driven check of all four blend modes, and that the lowest layer ignores its
|
||||
blend mode. `BUILD_TESTS` is `OFF` in the checked-in build cache; flip it on to run them:
|
||||
|
||||
cmake -S . -B build -DBUILD_TESTS=ON
|
||||
cmake --build build --config Release --target libslic3r_tests -- -m
|
||||
./build/tests/libslic3r/Release/libslic3r_tests.exe "[TextureDisplacement]" --order rand
|
||||
|
||||
## Build notes
|
||||
|
||||
- Everything here lives in `libslic3r`/`libslic3r_gui`/`libslic3r_cgal` — no new external
|
||||
dependency, no `deps/` rebuild needed. CGAL's parameterization package was already vendored.
|
||||
- To build just this feature's code path fastest: `cmake --build build --config Release --target
|
||||
libslic3r_gui -- -m` (pulls in `libslic3r` and `libslic3r_cgal` as needed). The full app target
|
||||
is `OrcaSlicer_app_gui` (produces `build/src/Release/orca-slicer.exe`) — only needed to actually
|
||||
run and visually test, not to verify compilation.
|
||||
- `BUILD_TESTS` is `OFF` in the existing build cache; flip it on to actually run
|
||||
`test_texture_displacement.cpp`.
|
||||
@@ -1,326 +0,0 @@
|
||||
# Texture Displacement — Feature & Controls Guide
|
||||
|
||||
Texture Displacement is a paint-style gizmo that stamps height-map textures onto a model's surface
|
||||
and turns them into real relief — engraved or embossed detail — either as a live preview or baked
|
||||
into actual mesh geometry. You paint where the texture applies, stack multiple textures as blended
|
||||
layers, choose how each is projected onto the surface, and (for the unwrap projection) lay the result
|
||||
out by hand in a dedicated 2D **UV Editor** pane.
|
||||
|
||||
This document describes every feature and control. For the internal architecture and algorithms, see
|
||||
`TEXTURE_DISPLACEMENT.md`.
|
||||
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Quick start](#quick-start)
|
||||
2. [Entering the tool](#entering-the-tool)
|
||||
3. [Selection modes](#selection-modes)
|
||||
4. [View modes](#view-modes)
|
||||
5. [Auto update](#auto-update)
|
||||
6. [Texture layers](#texture-layers)
|
||||
7. [Per-layer settings](#per-layer-settings)
|
||||
8. [Projection methods](#projection-methods)
|
||||
9. [The UV Editor](#the-uv-editor)
|
||||
10. [Seams](#seams)
|
||||
11. [Adjust placement (on-model)](#adjust-placement-on-model)
|
||||
12. [Preparing the mesh: Subdivide & Remesh](#preparing-the-mesh-subdivide--remesh)
|
||||
13. [Baking & resetting](#baking--resetting)
|
||||
14. [Controls reference](#controls-reference)
|
||||
15. [Tips & limitations](#tips--limitations)
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Select an object and open the **Texture displacement** gizmo from the left toolbar.
|
||||
2. A texture layer is added automatically. Pick a texture from the layer's picker, or import your own.
|
||||
3. **Paint** the area you want the texture to affect (or press **Select whole model**).
|
||||
4. The relief appears live on the model. Tune **Depth**, **Tile size**, **Rotation**, etc.
|
||||
5. If the model is low-poly, use **Subdivide** or **Remesh** so there are enough vertices for detail.
|
||||
6. Press **Bake** to convert the preview into real geometry, or leave it as a live preview.
|
||||
|
||||
> The tool only ever affects the **painted** area. Everything you don't paint keeps its original
|
||||
> surface, and bake blends the relief seamlessly into it.
|
||||
|
||||
---
|
||||
|
||||
## Entering the tool
|
||||
|
||||
The gizmo lives on the left gizmo toolbar (icon: `toolbar_texture_displacement.svg`). Its settings
|
||||
panel opens beside the toolbar. You can **Dock panel / Undock panel** (top of the panel) to pin it or
|
||||
float it freely over the 3D view, and **Close** at the bottom exits the gizmo.
|
||||
|
||||
When you first open the tool on a never-textured object it starts with **one texture layer already
|
||||
added**, so you can paint straight away.
|
||||
|
||||
---
|
||||
|
||||
## Selection modes
|
||||
|
||||
Choose *how* you paint. All three write into the **active layer's** mask.
|
||||
|
||||
| Mode | What it does |
|
||||
|------|--------------|
|
||||
| **Brush** | Free-hand painting with a round brush. Shows a **Brush size** slider and a **Circle / Sphere** choice (circle = surface disc, sphere = 3D ball that also paints around curves). |
|
||||
| **Face** | Click a single triangle to paint it. |
|
||||
| **Connected area** | Click to flood-fill a region; the **Angle threshold** slider limits how far the fill spreads across changes in surface angle. |
|
||||
|
||||
- **Select whole model** — marks the entire model as painted for the active layer, instead of
|
||||
brushing it by hand.
|
||||
|
||||
---
|
||||
|
||||
## View modes
|
||||
|
||||
A row of icon buttons labelled **View** controls how the painted area is shown. The first four are a
|
||||
radio group; **Wireframe** is an independent toggle. Hover any icon for its tooltip.
|
||||
|
||||
| View | Meaning |
|
||||
|------|---------|
|
||||
| **Normal** | The true displaced geometry — exactly what **Bake** produces. Rebuilt in the background. |
|
||||
| **Fast** | A GPU bump-shaded approximation of the *active layer only*. No real geometry movement — quick to update, not exact. Best while tuning or dragging islands. |
|
||||
| **Checker** | A test grid painted over the unwrap so you can see stretching (squares stay square where the map isn't distorted). |
|
||||
| **Distortion** | A blue→green→red heatmap of how much each area is compressed or stretched in UV space. Needs the **Unwrap (LSCM)** projection. |
|
||||
| **Wireframe** | Overlays the mesh edges (white). Independent of the view above; in **Normal** view it sits on the displaced surface. |
|
||||
|
||||
---
|
||||
|
||||
## Auto update
|
||||
|
||||
**Auto update** (on by default) rebuilds the true displaced geometry as soon as *anything* changes —
|
||||
painting, swapping textures, moving sliders. Turn it off on very heavy models to only rebuild when you
|
||||
release a slider (painting still updates on stroke end).
|
||||
|
||||
---
|
||||
|
||||
## Texture layers
|
||||
|
||||
You can stack up to **8** texture layers. Each has its own independent paint mask, its own texture,
|
||||
and its own parameters, and they combine in slot order like layers in an image editor.
|
||||
|
||||
- **Add a layer** — the **+ icon** to the right of the *Texture layers* heading (reuses the tool icon
|
||||
for now).
|
||||
- **Remove** — the button on each layer's header row.
|
||||
- **Active layer** — click a layer's header (or anywhere in its block) to make it active. The active
|
||||
layer is the one you paint into and the one whose block is tinted. Only one layer is active at a time.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
|
||||
Each layer shows a texture **picker** (large preview + name). Open it to choose from the shipped
|
||||
library or import your own image (any png/jpg/bmp; it's converted to an 8-bit grayscale height map and
|
||||
copied into your user texture folder so app updates can't overwrite it).
|
||||
|
||||
---
|
||||
|
||||
## Per-layer settings
|
||||
|
||||
| Control | Range / options | What it does |
|
||||
|---------|-----------------|--------------|
|
||||
| **Depth (mm)** | 0.01–10 (log) | Maximum displacement along the surface normal. |
|
||||
| **Tile size (mm)** | 0.2–200 (log) | Physical size of one texture tile on the surface. |
|
||||
| **Rotation** | 0–360° | Rotates the texture on the surface. |
|
||||
| **Midlevel** | 0–10 | The grey level that means "don't move". At 0 the texture only pushes outward; raise it and darker texels cut *inward* (one map both embosses and engraves). 0.5 makes mid-grey neutral. |
|
||||
| **Smoothing** | 0–1 | Blurs the height texture before it displaces — rounds hard edges and removes speckle without needing a softer source image. |
|
||||
| **Edge smoothing** | checkbox + **Edge amount** 0–1 | Fades the relief to flat toward the *edge of the painted area*, so it blends into the surrounding surface. A small amount softens only a thin band at the very edge; the maximum flattens the whole painted face. |
|
||||
| **Invert** | checkbox | Flips the height map (peaks become valleys). |
|
||||
| **Blend** | Add / Subtract / Multiply / Divide | How this layer combines with the layers **below** it where they overlap. Add/Subtract pile relief on or carve it away; Multiply/Divide scale the relief underneath (a mask). The lowest painted layer is the **Base** and always behaves additively. |
|
||||
| **Tile** | checkbox + **Repeat / Mirrored repeat** | When off, the texture is placed once (a decal) instead of repeating. Mirrored repeat flips every other tile to hide seams. |
|
||||
| **Projection** | see below | How the texture is mapped onto the painted surface. |
|
||||
|
||||
> **Midlevel warning:** cutting inward can fold the surface through itself in sharp concave corners or
|
||||
> thin walls. Keep Depth small relative to the feature you're cutting into; the panel warns when a deep
|
||||
> inward setting is risky.
|
||||
|
||||
---
|
||||
|
||||
## Projection methods
|
||||
|
||||
How the 2D texture is wrapped onto the 3D painted area.
|
||||
|
||||
| Method | Best for | Notes |
|
||||
|--------|----------|-------|
|
||||
| **Triplanar (blended)** | Patches wrapping around edges | Projects from all three axes at once and blends, so there's no seam across a sharp edge. |
|
||||
| **Cylindrical** | Round, tube-like selections | Wraps the texture around the patch's own centre/axis. |
|
||||
| **Spherical** | Ball-like selections | Longitude/latitude wrap around the patch centre. |
|
||||
| **Unwrap (LSCM)** | Flat, controlled layout | A real conformal unwrap. Cuts the area into pieces at sharp edges (see **Seam angle**), flattens each, and lets you lay them out by hand in the **UV Editor**. Unlocks Checker/Distortion, seams, and island editing. |
|
||||
| **From view** | Decals / slide-projector look | Projects straight onto the surface from the current camera direction. Use **Capture current view** to re-lay it from wherever you're looking. |
|
||||
|
||||
### LSCM-only controls
|
||||
|
||||
These appear when a layer uses **Unwrap (LSCM)**:
|
||||
|
||||
- **Seam angle** (5–90°) — edges sharper than this are cut so each piece lies flat. Lower cuts more
|
||||
(less stretching, more seams); raise to keep more in one piece. A box's 90° corners are cut by
|
||||
default. *Ignored once you've marked any seam by hand* (your seams then define the pieces).
|
||||
- **Connect islands** (on by default) — lays the unwrap out as a **connected net**: pieces that share
|
||||
an edge are unfolded next to each other (a cube becomes a joined net instead of six loose squares).
|
||||
They stay separate islands, so you can still move any of them by hand. Turn off for the classic
|
||||
packed-grid layout.
|
||||
- **Open UV editor** — shows the flattened unwrap in a side pane (see below). Opens *only* when you
|
||||
turn this on — it never pops up on its own.
|
||||
- **Mark seams** / **Path** / **Clear seams** — see [Seams](#seams).
|
||||
- An **Unwrap: N islands, F faces, V verts** read-out tells you what the unwrap actually produced.
|
||||
|
||||
---
|
||||
|
||||
## The UV Editor
|
||||
|
||||
A dockable 2D pane (enable **Open UV editor** on an LSCM layer) showing the flattened unwrap over the
|
||||
height texture. Islands are the flattened pieces; you can rearrange them freely — nothing re-packs them
|
||||
behind your back. Moving an island updates the model **live** (in Fast view it tracks the cursor
|
||||
smoothly, via a shader uniform — no rebuild until you release).
|
||||
|
||||
### Navigation
|
||||
|
||||
| Action | Control |
|
||||
|--------|---------|
|
||||
| Pan | Middle-drag |
|
||||
| Zoom | Mouse wheel (zooms about the cursor) |
|
||||
| Frame everything | **Home** or **F**, or the **Frame** toolbar button |
|
||||
|
||||
### Editing an island
|
||||
|
||||
| Action | Control |
|
||||
|--------|---------|
|
||||
| Select | Left-click an island |
|
||||
| Move | Left-drag |
|
||||
| Rotate | Right-drag, or press **R** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Rotate snapped | Hold **Shift** while rotating — snaps to **global** 15° marks (0/15/30…). A protractor dial with tick marks and the current angle is shown. |
|
||||
| Scale | Press **S** then move the mouse (click/Enter to confirm, Esc to cancel) |
|
||||
| Undo / Redo | **Ctrl+Z** / **Ctrl+Shift+Z** or **Ctrl+Y** |
|
||||
|
||||
The **selected** island gets a bold light-green outline and a brighter wireframe; unselected islands
|
||||
are a translucent light-green wash. The texture underneath repeats exactly as it will when baked.
|
||||
A **status line** along the bottom always names the current gesture and the shortcuts in play.
|
||||
|
||||
### Toolbar
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| **Frame** | Frame all islands (same as Home). |
|
||||
| **Snap** | Toggle magnetic snapping — a dragged island sticks its boundary to a neighbour's when they come close. |
|
||||
| **Avg scale** | Give every island the same texel density (Blender's "Average Islands Scale"). |
|
||||
| **Cut** | Split the selected island across its long axis (useful for very long islands). |
|
||||
| **Join** | Unfold the selected island onto its nearest neighbour along their shared edge — keeps both as separate islands with their own borders. |
|
||||
| **Unjoin** | Send the selected island back to its own packed position. |
|
||||
|
||||
> **Checker / Distortion in the UV editor:** selecting those View modes also colours the UV pane — a
|
||||
> checker background, or a per-island distortion heatmap — so you can judge stretch in 2D as well as
|
||||
> on the model.
|
||||
|
||||
---
|
||||
|
||||
## Seams
|
||||
|
||||
Seams are edges the unwrap is forced to cut along, on top of whatever the Seam angle cuts — the
|
||||
Blender "mark seam" workflow. They let you control exactly where the unwrap splits.
|
||||
|
||||
Enable **Mark seams** on an active LSCM layer, then:
|
||||
|
||||
- **Click an edge** on the model to mark it (it turns **red**); click a red edge again to unmark it.
|
||||
The edge under the cursor is highlighted **yellow** so you can see what a click will toggle.
|
||||
- **Path mode** (the **Path** checkbox) — for dense meshes where clicking each edge is tedious: click a
|
||||
start point, then an end point, and the whole **shortest path** between them is seamed at once. It
|
||||
chains (each click extends from the last point); the start vertex is shown in **green**.
|
||||
- **Ctrl+drag** rotates/pans the camera while in seam mode.
|
||||
- **Clear seams** removes them all.
|
||||
|
||||
Once any seam is marked, the automatic Seam-angle cutting is disabled so *your* seams define the
|
||||
islands — pieces you leave un-seamed merge together.
|
||||
|
||||
---
|
||||
|
||||
## Adjust placement (on-model)
|
||||
|
||||
**Adjust placement** (on an active layer) lets you position the texture by dragging a handle on the
|
||||
model instead of nudging the Rotation/offset numbers. The handle is a flat panel in the patch's
|
||||
tangent plane (drag anywhere on it to move freely) plus U/V arrows for single-axis nudges. It's
|
||||
anchored to the painted patch, so paint something first.
|
||||
|
||||
---
|
||||
|
||||
## Preparing the mesh: Subdivide & Remesh
|
||||
|
||||
Displacement can only move vertices that exist, so a coarse model needs more of them first.
|
||||
|
||||
### Subdivide
|
||||
|
||||
Splits every triangle into four, **1–5 times** (each step roughly quadruples the triangle count).
|
||||
|
||||
- **Subdivide steps** (1–5) — how many times to split.
|
||||
- **Preview subdivision** — shows the result as a **cyan wireframe** without changing the model.
|
||||
- **Apply** — commits the subdivision to the geometry.
|
||||
- **Done** — ends the preview and leaves the model as it is.
|
||||
|
||||
### Remesh
|
||||
|
||||
Rebuilds the whole model with triangles close to a target edge length — evens out a mesh with wildly
|
||||
varying triangle sizes (CGAL isotropic remeshing).
|
||||
|
||||
- **Target edge (mm)** — desired triangle edge length (seeded to the model's current average).
|
||||
- **Remesh** — splits the big triangles and merges the small ones to that size.
|
||||
|
||||
> Both Subdivide-Apply and Remesh **replace the geometry** and clear any *not-yet-baked* paint on it
|
||||
> (already-baked relief is kept). If you had the mesh **Wireframe** on before, it stays on afterward.
|
||||
|
||||
---
|
||||
|
||||
## Baking & resetting
|
||||
|
||||
- **Bake** — converts the current preview into real, permanent mesh geometry, restricted to the
|
||||
painted area. Runs in the background; the button shows *Baking…* while it works.
|
||||
- **Erase all** — clears the active layer's paint.
|
||||
|
||||
Baking is the exact same algorithm as the **Normal** preview, so what you see is what you get.
|
||||
|
||||
---
|
||||
|
||||
## Controls reference
|
||||
|
||||
### Mouse — 3D view (while painting)
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Left-drag | Paint the active layer |
|
||||
| Ctrl + drag | Rotate / pan the camera (works in seam mode too) |
|
||||
| Wheel | Zoom |
|
||||
|
||||
### Mouse & keys — UV Editor
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Left-click | Select island |
|
||||
| Left-drag | Move island |
|
||||
| Right-drag | Rotate island |
|
||||
| **R** / **S** | Modal rotate / scale (mouse drives it, click or Enter confirms, Esc cancels) |
|
||||
| **Shift** (while rotating) | Snap to global 15° marks |
|
||||
| Middle-drag | Pan |
|
||||
| Wheel | Zoom about cursor |
|
||||
| **Home** / **F** | Frame all islands |
|
||||
| **Ctrl+Z** / **Ctrl+Shift+Z** / **Ctrl+Y** | Undo / redo |
|
||||
|
||||
### Seam mode
|
||||
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| Click edge | Mark / unmark a seam (yellow = hover, red = marked) |
|
||||
| Click (Path mode) | Set start, then seam the shortest path to the next click |
|
||||
| Ctrl + drag | Rotate / pan camera |
|
||||
|
||||
---
|
||||
|
||||
## Tips & limitations
|
||||
|
||||
- **Paint first, then bake.** The preview is free to explore; only Bake changes the real mesh.
|
||||
- **Not enough detail?** Subdivide or Remesh before painting fine textures.
|
||||
- **Inward cuts** (high Midlevel + big Depth) can self-intersect on thin walls or sharp concave
|
||||
corners — keep Depth modest there.
|
||||
- **Fast vs Normal:** Fast preview shades a bump and shows only the active layer; use it for quick
|
||||
tuning and smooth UV dragging, but trust **Normal**/**Bake** for the exact result.
|
||||
- **Topology changes drop unbaked paint.** Subdivide-Apply, Remesh, and Simplify replace the mesh, and
|
||||
texture-displacement paint isn't remapped across that change (already-baked relief is unaffected).
|
||||
- **Island placements** are tied to the current unwrap. Re-painting or changing the Seam angle can
|
||||
re-segment the charts and renumber them, so a re-unwrap re-lays the connected net and discards
|
||||
hand placements made before it.
|
||||
- **Connect islands** is on by default; turn it off (per layer) for the classic packed-grid layout, or
|
||||
if an unfold looks wrong on an unusual mesh.
|
||||
5821
bbl/i18n/BambuStudio.pot
Normal file
17765
bbl/i18n/de/BambuStudio_de.po
Normal file
7090
bbl/i18n/en/BambuStudio_en.po
Normal file
17650
bbl/i18n/es/BambuStudio_es.po
Normal file
7479
bbl/i18n/fr/BambuStudio_fr.po
Normal file
109
bbl/i18n/list.txt
Normal file
@@ -0,0 +1,109 @@
|
||||
src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
|
||||
src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp
|
||||
src/slic3r/GUI/Gizmos/GLGizmoModifier.cpp
|
||||
src/slic3r/GUI/GUI.cpp
|
||||
src/slic3r/GUI/GUI_App.cpp
|
||||
src/slic3r/GUI/GUI_Init.cpp
|
||||
src/slic3r/GUI/GUI_Factories.cpp
|
||||
src/slic3r/GUI/GUI_ObjectList.cpp
|
||||
src/slic3r/GUI/GUI_ObjectSettings.cpp
|
||||
src/slic3r/GUI/GUI_ObjectTable.cpp
|
||||
src/slic3r/GUI/GUI_ObjectTable.hpp
|
||||
src/slic3r/GUI/GUI_ObjectTableSettings.cpp
|
||||
src/slic3r/GUI/GUI_ObjectTableSettings.hpp
|
||||
src/slic3r/GUI/GUI_Preview.cpp
|
||||
src/slic3r/GUI/Widgets/SideTools.cpp
|
||||
src/slic3r/GUI/Widgets/AMSControl.cpp
|
||||
src/slic3r/GUI/ImGuiWrapper.cpp
|
||||
src/slic3r/GUI/Jobs/ArrangeJob.cpp
|
||||
src/slic3r/GUI/Jobs/OrientJob.cpp
|
||||
src/slic3r/GUI/Jobs/FillBedJob.cpp
|
||||
src/slic3r/GUI/Jobs/Job.cpp
|
||||
src/slic3r/GUI/Jobs/PlaterJob.cpp
|
||||
src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
|
||||
src/slic3r/GUI/Jobs/BindJob.cpp
|
||||
src/slic3r/GUI/Jobs/PrintJob.cpp
|
||||
src/slic3r/GUI/AboutDialog.cpp
|
||||
src/slic3r/GUI/AMSMaterialsSetting.cpp
|
||||
src/slic3r/GUI/AMSSetting.cpp
|
||||
src/slic3r/GUI/BBLTopbar.cpp
|
||||
src/slic3r/GUI/BackgroundSlicingProcess.cpp
|
||||
src/slic3r/GUI/BedShapeDialog.cpp
|
||||
src/slic3r/GUI/BedShapeDialog.hpp
|
||||
src/slic3r/GUI/ConfigManipulation.cpp
|
||||
src/slic3r/GUI/DeviceManager.cpp
|
||||
src/slic3r/GUI/ExtraRenderers.cpp
|
||||
src/slic3r/GUI/Field.cpp
|
||||
src/slic3r/GUI/GCodeViewer.cpp
|
||||
src/slic3r/GUI/GLCanvas3D.cpp
|
||||
src/slic3r/GUI/Calibration.cpp
|
||||
src/slic3r/GUI/CameraPopup.cpp
|
||||
src/slic3r/GUI/ConnectPrinter.cpp
|
||||
src/slic3r/GUI/DebugToolDialog.cpp
|
||||
src/slic3r/GUI/HMSPanel.cpp
|
||||
src/slic3r/GUI/MainFrame.cpp
|
||||
src/slic3r/GUI/MediaPlayCtrl.cpp
|
||||
src/slic3r/GUI/Mouse3DController.cpp
|
||||
src/slic3r/GUI/StatusPanel.cpp
|
||||
src/slic3r/GUI/Monitor.cpp
|
||||
src/slic3r/GUI/MsgDialog.cpp
|
||||
src/slic3r/GUI/NotificationManager.hpp
|
||||
src/slic3r/GUI/NotificationManager.cpp
|
||||
src/slic3r/GUI/ObjectDataViewModel.cpp
|
||||
src/slic3r/GUI/OpenGLManager.cpp
|
||||
src/slic3r/GUI/OptionsGroup.cpp
|
||||
src/slic3r/GUI/ParamsPanel.cpp
|
||||
src/slic3r/GUI/PartPlate.cpp
|
||||
src/slic3r/GUI/Plater.cpp
|
||||
src/slic3r/GUI/Preferences.cpp
|
||||
src/slic3r/GUI/PresetComboBoxes.cpp
|
||||
src/slic3r/GUI/PresetHints.cpp
|
||||
src/slic3r/GUI/ProgressStatusBar.cpp
|
||||
src/slic3r/GUI/PublishDialog.cpp
|
||||
src/slic3r/GUI/SavePresetDialog.cpp
|
||||
src/slic3r/GUI/Search.cpp
|
||||
src/slic3r/GUI/Selection.cpp
|
||||
src/slic3r/GUI/SelectMachine.cpp
|
||||
src/slic3r/GUI/SendSystemInfoDialog.cpp
|
||||
src/slic3r/GUI/BindDialog.cpp
|
||||
src/slic3r/GUI/Tab.cpp
|
||||
src/slic3r/GUI/Tab.hpp
|
||||
src/slic3r/GUI/UnsavedChangesDialog.cpp
|
||||
src/slic3r/GUI/Auxiliary.cpp
|
||||
src/slic3r/GUI/UpdateDialogs.cpp
|
||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
src/slic3r/GUI/wxExtensions.cpp
|
||||
src/slic3r/GUI/WebUserLoginDialog.cpp
|
||||
src/slic3r/GUI/WebGuideDialog.cpp
|
||||
src/slic3r/GUI/KBShortcutsDialog.hpp
|
||||
src/slic3r/GUI/KBShortcutsDialog.cpp
|
||||
src/slic3r/Utils/FixModelByWin10.cpp
|
||||
src/slic3r/Utils/PresetUpdater.cpp
|
||||
src/slic3r/Utils/Http.cpp
|
||||
src/slic3r/Utils/Process.cpp
|
||||
src/slic3r/GUI/Jobs/PrintJob.cpp
|
||||
src/libslic3r/GCode.cpp
|
||||
src/libslic3r/ExtrusionEntity.cpp
|
||||
src/libslic3r/Flow.cpp
|
||||
src/libslic3r/Format/AMF.cpp
|
||||
src/libslic3r/miniz_extension.cpp
|
||||
src/libslic3r/Preset.cpp
|
||||
src/libslic3r/Print.cpp
|
||||
src/libslic3r/PrintBase.cpp
|
||||
src/libslic3r/PrintConfig.cpp
|
||||
src/libslic3r/Zipper.cpp
|
||||
src/libslic3r/PrintObject.cpp
|
||||
src/libslic3r/PrintObjectSlice.cpp
|
||||
src/libslic3r/PlaceholderParser.cpp
|
||||
src/libslic3r/TreeSupport.cpp
|
||||
|
||||
7504
bbl/i18n/nl/BambuStudio_nl.po
Normal file
7322
bbl/i18n/sv/BambuStudio_sv.po
Normal file
9599
bbl/i18n/zh_cn/BambuStudio_zh_CN.po
Normal file
4
bbs_test_tools/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# Add individual tools as executables in separate directories
|
||||
add_subdirectory(bbs_gcode_checker)
|
||||
|
||||
install(TARGETS bbs_gcode_checker RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
6
bbs_test_tools/bbs_gcode_checker/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required (VERSION 3.8)
|
||||
|
||||
project ("bbs_gcode_checker")
|
||||
|
||||
add_executable (bbs_gcode_checker "main.cpp" "GCodeChecker.cpp" "GCodeChecker.h" )
|
||||
|
||||
602
bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
#include "GCodeChecker.h"
|
||||
#include <fstream>
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
|
||||
namespace BambuStudio {
|
||||
|
||||
//BBS: only check wodth when dE is longer than this value
|
||||
const double CHECK_WIDTH_E_THRESHOLD = 0.0025;
|
||||
const double WIDTH_THRESHOLD = 0.012;
|
||||
const double RADIUS_THRESHOLD = 0.005;
|
||||
|
||||
const double filament_diameter = 1.75;
|
||||
const double Pi = 3.14159265358979323846;
|
||||
|
||||
const std::string Extrusion_Role_Tag = " FEATURE: ";
|
||||
const std::string Width_Tag = " LINE_WIDTH: ";
|
||||
const std::string Wipe_Start_Tag = " WIPE_START";
|
||||
const std::string Wipe_End_Tag = " WIPE_END";
|
||||
const std::string Layer_Change_Tag = " CHANGE_LAYER";
|
||||
const std::string Height_Tag = " LAYER_HEIGHT: ";
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_file(const std::string& path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
if (file.fail()) {
|
||||
std::cout << "Failed to open file " << path << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
std::string line_raw;
|
||||
std::string line;
|
||||
while (std::getline(file, line_raw)) {
|
||||
const char *c = line_raw.c_str();
|
||||
c = skip_whitespaces(c);
|
||||
if (std::toupper(*c) == 'N')
|
||||
c = skip_word(c);
|
||||
c = skip_whitespaces(c);
|
||||
line = c;
|
||||
if (parse_line(line) != GCodeCheckResult::Success) {
|
||||
std::cout << "Failed to parse line " << line_raw << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_layer_num == 0) {
|
||||
std::cout << "Invalid gcode file without layer change comment" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
bool GCodeChecker::include_chinese(const char* str)
|
||||
{
|
||||
char c;
|
||||
while(1)
|
||||
{
|
||||
c=*str++;
|
||||
if (is_end_of_line(c))
|
||||
break;
|
||||
if ((c & 0x80) && (*str & 0x80))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_line(const std::string& line)
|
||||
{
|
||||
// update start position
|
||||
m_start_position = m_end_position;
|
||||
|
||||
GCodeCheckResult ret;
|
||||
const char *c = skip_whitespaces(line.c_str());
|
||||
if (include_chinese(c)) {
|
||||
//chinese is forbidden
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
} if (is_end_of_line(*c)) {
|
||||
//BBS: skip empty line
|
||||
return GCodeCheckResult::Success;
|
||||
} else if (is_comment_line(*c)) {
|
||||
GCodeLine gcode_line;
|
||||
gcode_line.m_raw = c;
|
||||
ret = parse_comment(gcode_line);
|
||||
if (ret != GCodeCheckResult::Success)
|
||||
return ret;
|
||||
} else {
|
||||
GCodeLine gcode_line;
|
||||
gcode_line.m_raw = c;
|
||||
ret = parse_command(gcode_line);
|
||||
if (ret != GCodeCheckResult::Success)
|
||||
return ret;
|
||||
ret = check_line_width(gcode_line);
|
||||
if (ret != GCodeCheckResult::Success)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_comment(GCodeLine& line)
|
||||
{
|
||||
const char *c = line.m_raw.c_str();
|
||||
c++;
|
||||
std::string comment = c;
|
||||
// extrusion role tag
|
||||
if (starts_with(comment, Extrusion_Role_Tag)) {
|
||||
m_role = string_to_role(comment.substr(Extrusion_Role_Tag.length()));
|
||||
} else if (starts_with(comment, Wipe_Start_Tag)) {
|
||||
m_wiping = true;
|
||||
} else if (starts_with(comment, Wipe_End_Tag)) {
|
||||
m_wiping = false;
|
||||
} else if (starts_with(comment, Height_Tag)) {
|
||||
std::string str = comment.substr(Height_Tag.size());
|
||||
if (!parse_double_from_str(str, m_height)) {
|
||||
std::cout << "invalid height comment with invalid value!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
} else if (starts_with(comment, Width_Tag)) {
|
||||
std::string str = comment.substr(Width_Tag.size());
|
||||
if (!parse_double_from_str(str, m_width)) {
|
||||
std::cout << "invalid width comment with invalid value!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
} else if (starts_with(comment, Layer_Change_Tag)) {
|
||||
m_layer_num++;
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_command(GCodeLine& gcode_line)
|
||||
{
|
||||
const std::string cmd = gcode_line.cmd();
|
||||
GCodeCheckResult ret = GCodeCheckResult::Success;
|
||||
switch (::toupper(cmd[0])) {
|
||||
case 'G':
|
||||
{
|
||||
switch (::atoi(&cmd[1]))
|
||||
{
|
||||
case 0:
|
||||
case 1: { ret = parse_G0_G1(gcode_line); break; } // Move
|
||||
case 2:
|
||||
case 3: { ret = parse_G2_G3(gcode_line); break; } // Move
|
||||
case 90: { ret = parse_G90(gcode_line); break; } // Set to Absolute Positioning
|
||||
case 91: { ret = parse_G91(gcode_line); break; } // Set to Relative Positioning
|
||||
case 92: { ret = parse_G92(gcode_line); break; } // Set Position
|
||||
default: { break; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'M':{
|
||||
switch (::atoi(&cmd[1]))
|
||||
{
|
||||
case 82: { ret = parse_M82(gcode_line); break; } // Set to Absolute extrusion
|
||||
case 83: { ret = parse_M83(gcode_line); break; } // Set to Relative extrusion
|
||||
default: { break; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'T':{
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
//BBS: other g command? impossible! must be invalid
|
||||
ret = GCodeCheckResult::ParseFailed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_axis(GCodeLine& gcode_line)
|
||||
{
|
||||
const std::string cmd = gcode_line.m_raw;
|
||||
const char* c = cmd.c_str();
|
||||
c = skip_word(c);
|
||||
while (! is_end_of_gcode_line(*c)) {
|
||||
c = skip_whitespaces(c);
|
||||
if (is_end_of_gcode_line(*c))
|
||||
break;
|
||||
|
||||
Axis axis = UNKNOWN_AXIS;
|
||||
switch (*c) {
|
||||
case 'X': axis = X; break;
|
||||
case 'Y': axis = Y; break;
|
||||
case 'Z': axis = Z; break;
|
||||
case 'E': axis = E; break;
|
||||
case 'F': axis = F; break;
|
||||
case 'I': axis = I; break;
|
||||
case 'J': axis = J; break;
|
||||
default:
|
||||
//BBS: invalid command which has invalid axis
|
||||
std::cout << "Invalid gcode because of invalid axis!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
|
||||
char *pend = nullptr;
|
||||
double v = strtod(++c, &pend);
|
||||
if (pend != nullptr && is_end_of_word(*pend) && !isnan(v) && !isinf(v)) {
|
||||
gcode_line.m_axis[int(axis)] = v;
|
||||
if (gcode_line.m_mask & (1 << int(axis))) {
|
||||
//BBS: invalid command which has duplicated axis
|
||||
std::cout << "Invalid gcode because of duplicated axis!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
} else {
|
||||
gcode_line.m_mask |= 1 << int(axis);
|
||||
}
|
||||
if (c == pend) {
|
||||
//BBS: invalid command which has invalid axis value
|
||||
std::cout << "Invalid gcode because of invalid axis value!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
c = pend;
|
||||
} else {
|
||||
//BBS: invalid command for invalid axis value
|
||||
std::cout << "Invalid gcode because of invalid axis value!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_G0_G1(GCodeLine& gcode_line)
|
||||
{
|
||||
if (parse_axis(gcode_line) != GCodeCheckResult::Success)
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
|
||||
//BBS: invalid G1 command which has no axis or invalid axis
|
||||
if ((!gcode_line.m_mask) ||
|
||||
gcode_line.has(I) ||
|
||||
gcode_line.has(J)) {
|
||||
std::cout << "Invalid G0_G1 gcode because of no axis or invalid axis!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
|
||||
//BBS: invalid G1 command which has zero speed
|
||||
if (gcode_line.has(F) && gcode_line.get(F) == 0.0) {
|
||||
std::cout << "Invalid G0_G1 gcode because has F axis but 0 speed!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_G2_G3(GCodeLine& gcode_line)
|
||||
{
|
||||
if (parse_axis(gcode_line) != GCodeCheckResult::Success)
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
|
||||
//BBS: invalid G2_G3 command which has no axis or Z axis
|
||||
if (!gcode_line.m_mask) {
|
||||
std::cout << "Invalid G2_G3 gcode because of no axis or has Z axis!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
//BBS: invalid G2_G3 command which has zero speed
|
||||
if (gcode_line.has(F) && gcode_line.get(F) == 0.0) {
|
||||
std::cout << "Invalid G2_G3 gcode because has F axis but 0 speed!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
//BBS: invalid G2_G3 command which has no I and J axis
|
||||
if (!gcode_line.has(I) &&
|
||||
!gcode_line.has(J)) {
|
||||
std::cout << "Invalid G2_G3 gcode because of no I and J axis at same time!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
//BBS: invalid G2_G3 command which has no X and Y axis at same time
|
||||
if (!gcode_line.has(X) &&
|
||||
!gcode_line.has(Y)) {
|
||||
if (!gcode_line.has(X) || !gcode_line.has(P) || (int)gcode_line.get(P) != 1) {
|
||||
std::cout << "Invalid G2_G3 gcode because of no X and Y axis at same time!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_G90(const GCodeLine& gcode_line)
|
||||
{
|
||||
const char* c = gcode_line.m_raw.c_str();
|
||||
//BBS: G90 is single command with no argument
|
||||
if (!is_single_gcode_word(c)) {
|
||||
std::cout << "Invalid G90 gcode with invalid end!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
m_global_positioning_type = EPositioningType::Absolute;
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_G91(const GCodeLine& gcode_line)
|
||||
{
|
||||
const char* c = gcode_line.m_raw.c_str();
|
||||
//BBS: G91 is single command with no argument
|
||||
if (!is_single_gcode_word(c)) {
|
||||
std::cout << "Invalid G91 gcode with invalid end!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
m_global_positioning_type = EPositioningType::Relative;
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_G92(GCodeLine& gcode_line)
|
||||
{
|
||||
if (parse_axis(gcode_line) != GCodeCheckResult::Success)
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
|
||||
//BBS: invalid G92 command which has no axis or invalid axis
|
||||
if (!gcode_line.m_mask ||
|
||||
gcode_line.has(F) ||
|
||||
gcode_line.has(I) ||
|
||||
gcode_line.has(J)) {
|
||||
std::cout << "Invalid G2_G3 gcode because of no axis or invalid axis!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
|
||||
if (gcode_line.has(X))
|
||||
m_origin[X] = m_end_position[X] - gcode_line.get(X);
|
||||
|
||||
if (gcode_line.has(Y))
|
||||
m_origin[Y] = m_end_position[Y] - gcode_line.get(Y);
|
||||
|
||||
if (gcode_line.has(Z))
|
||||
m_origin[Z] = m_end_position[Z] - gcode_line.get(Z);
|
||||
|
||||
if (gcode_line.has(E))
|
||||
m_end_position[E] = gcode_line.get(E);
|
||||
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
m_origin[a] = m_end_position[a];
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_M82(const GCodeLine& gcode_line)
|
||||
{
|
||||
const char* c = gcode_line.m_raw.c_str();
|
||||
//BBS: M82 is single command with no argument
|
||||
if (!is_single_gcode_word(c)) {
|
||||
std::cout << "Invalid M82 gcode with invalid end!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
m_e_local_positioning_type = EPositioningType::Absolute;
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::parse_M83(const GCodeLine& gcode_line)
|
||||
{
|
||||
const char* c = gcode_line.m_raw.c_str();
|
||||
//BBS: M83 is single command with no argument
|
||||
if (!is_single_gcode_word(c)) {
|
||||
std::cout << "Invalid M83 gcode with invalid end!" << std::endl;
|
||||
return GCodeCheckResult::ParseFailed;
|
||||
}
|
||||
m_e_local_positioning_type = EPositioningType::Relative;
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
double GCodeChecker::calculate_G1_width(const std::array<double, 3>& source,
|
||||
const std::array<double, 3>& target,
|
||||
double e, double height, bool is_bridge) const
|
||||
{
|
||||
double volume = e * Pi * (filament_diameter/2.0f) * (filament_diameter/2.0f);
|
||||
std::array<double, 3> delta = { target[0] - source[0],
|
||||
target[1] - source[1],
|
||||
target[2] - source[2] };
|
||||
double length = sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
|
||||
double mm3_per_mm = volume / length;
|
||||
return is_bridge? 2 * sqrt(mm3_per_mm/Pi) :
|
||||
(mm3_per_mm / height) + height * (1 - 0.25 * Pi);
|
||||
}
|
||||
|
||||
double GCodeChecker::calculate_G2_G3_width(const std::array<double, 2>& source,
|
||||
const std::array<double, 2>& target,
|
||||
const std::array<double, 2>& center,
|
||||
bool is_ccw, double e, double height,
|
||||
bool is_bridge) const
|
||||
{
|
||||
std::array<double, 2> v1 = { source[0] - center[0], source[1] - center[1] };
|
||||
std::array<double, 2> v2 = { target[0] - center[0], target[1] - center[1] };
|
||||
|
||||
double dot = v1[0] * v2[0] + v1[1] * v2[1];
|
||||
double cross = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
double radian = atan2(cross, dot);
|
||||
radian = is_ccw ?
|
||||
(radian < 0 ? 2 * Pi + radian : radian) :
|
||||
(radian < 0 ? -radian : 2 * Pi - radian);
|
||||
double radius = sqrt(v1[0] * v1[0] + v1[1] * v1[1]);
|
||||
double length = radius * radian;
|
||||
double volume = e * Pi * (filament_diameter/2) * (filament_diameter/2);
|
||||
double mm3_per_mm = volume / length;
|
||||
return is_bridge? 2 * sqrt(mm3_per_mm/Pi) :
|
||||
(mm3_per_mm / height) + height * (1 - 0.25 * Pi);
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::check_line_width(const GCodeLine& gcode_line)
|
||||
{
|
||||
//BBS: don't need to check extrusion before first layer
|
||||
if (m_layer_num <= 0) {
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult ret = GCodeCheckResult::Success;
|
||||
//BBS: only need to handle G0 G1 G2 G3
|
||||
const std::string cmd = gcode_line.cmd();
|
||||
int cmd_id = ::atoi(&cmd[1]);
|
||||
if (::toupper(cmd[0]) == 'G')
|
||||
switch (::atoi(&cmd[1]))
|
||||
{
|
||||
case 0:
|
||||
case 1: { ret = check_G0_G1_width(gcode_line); break; }
|
||||
case 2:
|
||||
case 3: { ret = check_G2_G3_width(gcode_line); break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::check_G0_G1_width(const GCodeLine& line)
|
||||
{
|
||||
auto absolute_position = [this](Axis axis, const GCodeLine& lineG1) {
|
||||
bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
|
||||
if (axis == E)
|
||||
is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
|
||||
|
||||
if (lineG1.has(Axis(axis))) {
|
||||
double ret = lineG1.get(Axis(axis));
|
||||
return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
|
||||
} else
|
||||
return m_start_position[axis];
|
||||
};
|
||||
|
||||
auto move_type = [this](const std::array<double, 4>& delta_pos) {
|
||||
EMoveType type = EMoveType::Noop;
|
||||
|
||||
if (m_wiping)
|
||||
type = EMoveType::Wipe;
|
||||
else if (delta_pos[E] < 0.0f)
|
||||
type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
|
||||
else if (delta_pos[E] > 0.0f) {
|
||||
if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)
|
||||
type = (delta_pos[Z] == 0.0f) ? EMoveType::Unretract : EMoveType::Travel;
|
||||
else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f)
|
||||
type = EMoveType::Extrude;
|
||||
}
|
||||
else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f)
|
||||
type = EMoveType::Travel;
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
m_end_position[a] = absolute_position((Axis)a, line);
|
||||
}
|
||||
|
||||
// calculates movement deltas
|
||||
std::array<double, 4> delta_pos;
|
||||
for (unsigned char a = X; a <= E; ++a)
|
||||
delta_pos[a] = m_end_position[a] - m_start_position[a];
|
||||
|
||||
// Todo: currently, for precision, there alwasy has possible to generate
|
||||
// such gcode because of decimal truncation
|
||||
/*if (line.has(Axis(E)) && delta_pos[E] == 0.0 && !m_wiping) {
|
||||
std::cout << "Invalid GCode because has E axis but 0 extrusion" << std::endl;
|
||||
return GCodeCheckResult::CheckFailed;
|
||||
}*/
|
||||
|
||||
EMoveType type = move_type(delta_pos);
|
||||
if (type == EMoveType::Extrude && m_end_position[Z] == 0.0f)
|
||||
type = EMoveType::Travel;
|
||||
|
||||
//BBS: calculate line width and compare.
|
||||
//Don't need to check gap fill which has verious width
|
||||
if (type == EMoveType::Extrude &&
|
||||
m_role != erGapFill &&
|
||||
delta_pos[E] > CHECK_WIDTH_E_THRESHOLD) {
|
||||
std::array<double, 3> source = { m_start_position[X], m_start_position[Y], m_start_position[Z] };
|
||||
std::array<double, 3> target = { m_end_position[X], m_end_position[Y], m_end_position[Z] };
|
||||
|
||||
bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill;
|
||||
double width_real = calculate_G1_width(source, target, delta_pos[E], m_height, is_bridge);
|
||||
if (fabs(width_real - m_width) > WIDTH_THRESHOLD) {
|
||||
std::cout << "Invalid G0_G1 because has abnormal line width." << std::endl;
|
||||
std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl;
|
||||
return GCodeCheckResult::CheckFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
GCodeCheckResult GCodeChecker::check_G2_G3_width(const GCodeLine& line)
|
||||
{
|
||||
auto absolute_position = [this](Axis axis, const GCodeLine& lineG2_3) {
|
||||
bool is_relative = (m_global_positioning_type == EPositioningType::Relative);
|
||||
if (axis == E)
|
||||
is_relative |= (m_e_local_positioning_type == EPositioningType::Relative);
|
||||
|
||||
if (lineG2_3.has(Axis(axis))) {
|
||||
double ret = lineG2_3.get(Axis(axis));
|
||||
if (axis == I)
|
||||
return m_start_position[X] + ret;
|
||||
else if (axis == J)
|
||||
return m_start_position[Y] + ret;
|
||||
else
|
||||
return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
|
||||
} else {
|
||||
if (axis == I)
|
||||
return m_start_position[X];
|
||||
else if (axis == J)
|
||||
return m_start_position[Y];
|
||||
else
|
||||
return m_start_position[axis];
|
||||
}
|
||||
};
|
||||
|
||||
auto move_type = [this](const double& delta_E) {
|
||||
EMoveType type = EMoveType::Noop;
|
||||
|
||||
if (m_wiping)
|
||||
type = EMoveType::Wipe;
|
||||
else if (delta_E < 0.0f || delta_E == 0.0f)
|
||||
type = EMoveType::Travel;
|
||||
else
|
||||
type = EMoveType::Extrude;
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
for (unsigned char a = X; a <= E; ++a) {
|
||||
m_end_position[a] = absolute_position((Axis)a, line);
|
||||
}
|
||||
std::array<double, 2> source = { m_start_position[X], m_start_position[Y] };
|
||||
std::array<double, 2> target = { m_end_position[X], m_end_position[Y] };
|
||||
std::array<double, 2> center = { absolute_position(I, line),absolute_position(J, line) };
|
||||
const std::string& cmd = line.cmd();
|
||||
bool is_ccw = (::atoi(&cmd[1]) == 2) ? false : true;
|
||||
double delta_e = m_end_position[E] - m_start_position[E];
|
||||
EMoveType type = move_type(delta_e);
|
||||
|
||||
//BBS: judge whether is normal arc by radius
|
||||
double radius1 = sqrt(pow((source[0] - center[0]), 2) + pow((source[1] - center[1]), 2));
|
||||
double radius2 = sqrt(pow((target[0] - center[0]), 2) + pow((target[1] - center[1]), 2));
|
||||
if (fabs(radius2 - radius1) > RADIUS_THRESHOLD) {
|
||||
std::cout << "Invalid G2_G3 because of abnormal radius." << std::endl;
|
||||
std::cout << "radius1: " << radius1 << " radius2: " << radius2 << std::endl;
|
||||
return GCodeCheckResult::CheckFailed;
|
||||
}
|
||||
|
||||
//BBS: calculate line width and compare
|
||||
//Don't need to check gap fill which has verious width
|
||||
if (type == EMoveType::Extrude &&
|
||||
m_role != erGapFill &&
|
||||
delta_e > CHECK_WIDTH_E_THRESHOLD) {
|
||||
bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill;
|
||||
double width_real = calculate_G2_G3_width(source, target, center, is_ccw, delta_e, m_height, is_bridge);
|
||||
if (fabs(width_real - m_width) > WIDTH_THRESHOLD) {
|
||||
std::cout << "Invalid G2_G3 because has abnormal line width." << std::endl;
|
||||
std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl;
|
||||
return GCodeCheckResult::CheckFailed;
|
||||
}
|
||||
}
|
||||
|
||||
return GCodeCheckResult::Success;
|
||||
}
|
||||
|
||||
const std::map<std::string, ExtrusionRole> string_to_role_map = {
|
||||
{ "Inner wall", erPerimeter },
|
||||
{ "Outer wall", erExternalPerimeter },
|
||||
{ "Overhang wall", erOverhangPerimeter },
|
||||
{ "Sparse infill", erInternalInfill },
|
||||
{ "Internal solid infill", erSolidInfill },
|
||||
{ "Top surface", erTopSolidInfill },
|
||||
{ "Bottom surface", erBottomSurface },
|
||||
{ "Ironing", erIroning },
|
||||
{ "Bridge", erBridgeInfill },
|
||||
{ "Gap infill", erGapFill },
|
||||
{ "Skirt", erSkirt },
|
||||
{ "Brim", erBrim },
|
||||
{ "Support", erSupportMaterial },
|
||||
{ "Support interface", erSupportMaterialInterface },
|
||||
{ "Support transition", erSupportTransition },
|
||||
{ "Prime tower", erWipeTower },
|
||||
{ "Custom", erCustom },
|
||||
{ "Mixed", erMixed }
|
||||
};
|
||||
|
||||
ExtrusionRole GCodeChecker::string_to_role(const std::string &role)
|
||||
{
|
||||
for (auto it = string_to_role_map.begin(); it != string_to_role_map.end(); it++) {
|
||||
if (role == it->first)
|
||||
return it->second;
|
||||
}
|
||||
return erNone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
181
bbs_test_tools/bbs_gcode_checker/GCodeChecker.h
Normal file
@@ -0,0 +1,181 @@
|
||||
#ifndef _GCodeChecker_H_
|
||||
#define _GCodeChecker_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace BambuStudio {
|
||||
|
||||
enum class GCodeCheckResult : unsigned char
|
||||
{
|
||||
Success,
|
||||
ParseFailed,
|
||||
CheckFailed,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class EMoveType : unsigned char
|
||||
{
|
||||
Noop,
|
||||
Retract,
|
||||
Unretract,
|
||||
Tool_change,
|
||||
Color_change,
|
||||
Pause_Print,
|
||||
Custom_GCode,
|
||||
Travel,
|
||||
Wipe,
|
||||
Extrude,
|
||||
Count
|
||||
};
|
||||
|
||||
enum Axis {
|
||||
X=0,
|
||||
Y,
|
||||
Z,
|
||||
E,
|
||||
F,
|
||||
I,
|
||||
J,
|
||||
P,
|
||||
NUM_AXES,
|
||||
UNKNOWN_AXIS = NUM_AXES,
|
||||
};
|
||||
|
||||
enum ExtrusionRole : uint8_t {
|
||||
erNone,
|
||||
erPerimeter,
|
||||
erExternalPerimeter,
|
||||
erOverhangPerimeter,
|
||||
erInternalInfill,
|
||||
erSolidInfill,
|
||||
erTopSolidInfill,
|
||||
erBottomSurface,
|
||||
erIroning,
|
||||
erBridgeInfill,
|
||||
erGapFill,
|
||||
erSkirt,
|
||||
erBrim,
|
||||
erSupportMaterial,
|
||||
erSupportMaterialInterface,
|
||||
erSupportTransition,
|
||||
erWipeTower,
|
||||
erCustom,
|
||||
// Extrusion role for a collection with multiple extrusion roles.
|
||||
erMixed,
|
||||
erCount
|
||||
};
|
||||
|
||||
class GCodeChecker {
|
||||
public:
|
||||
class GCodeLine {
|
||||
public:
|
||||
GCodeLine() {}
|
||||
const std::string cmd() const {
|
||||
const char *cmd = GCodeChecker::skip_whitespaces(m_raw.c_str());
|
||||
return std::string(cmd, GCodeChecker::skip_word(cmd) - cmd);
|
||||
}
|
||||
|
||||
bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; }
|
||||
double get(Axis axis) const { return m_axis[int(axis)]; }
|
||||
|
||||
std::string m_raw;
|
||||
double m_axis[NUM_AXES] = { 0.0f };
|
||||
uint32_t m_mask = 0;
|
||||
};
|
||||
|
||||
enum class EPositioningType : unsigned char
|
||||
{
|
||||
Absolute,
|
||||
Relative
|
||||
};
|
||||
|
||||
GCodeChecker() {}
|
||||
GCodeCheckResult parse_file(const std::string& path);
|
||||
|
||||
private:
|
||||
bool include_chinese(const char* str);
|
||||
GCodeCheckResult parse_line(const std::string& line);
|
||||
|
||||
GCodeCheckResult parse_command(GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_axis(GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_G0_G1(GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_G2_G3(GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_G90(const GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_G91(const GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_G92(GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_M82(const GCodeLine& gcode_line);
|
||||
GCodeCheckResult parse_M83(const GCodeLine& gcode_line);
|
||||
|
||||
GCodeCheckResult parse_comment(GCodeLine& gcode_line);
|
||||
|
||||
GCodeCheckResult check_line_width(const GCodeLine& gcode_line);
|
||||
GCodeCheckResult check_G0_G1_width(const GCodeLine& gcode_line);
|
||||
GCodeCheckResult check_G2_G3_width(const GCodeLine& gcode_line);
|
||||
|
||||
double calculate_G1_width(const std::array<double, 3>& source,
|
||||
const std::array<double, 3>& target,
|
||||
double e, double height, bool is_bridge) const;
|
||||
double calculate_G2_G3_width(const std::array<double, 2>& source,
|
||||
const std::array<double, 2>& target,
|
||||
const std::array<double, 2>& center,
|
||||
bool is_ccw, double e, double height, bool is_bridge) const;
|
||||
|
||||
public:
|
||||
static bool is_whitespace(char c) { return c == ' ' || c == '\t'; }
|
||||
static bool is_end_of_line(char c) { return c == '\r' || c == '\n' || c == 0; }
|
||||
static bool is_comment_line(char c) { return c == ';'; }
|
||||
static bool is_end_of_gcode_line(char c) { return is_comment_line(c) || is_end_of_line(c); }
|
||||
static bool is_end_of_word(char c) { return is_whitespace(c) || is_end_of_gcode_line(c); }
|
||||
static const char* skip_word(const char *c) {
|
||||
for (; ! is_end_of_word(*c); ++ c)
|
||||
; // silence -Wempty-body
|
||||
return c;
|
||||
}
|
||||
static const char* skip_whitespaces(const char *c) {
|
||||
for (; is_whitespace(*c); ++ c)
|
||||
; // silence -Wempty-body
|
||||
return c;
|
||||
}
|
||||
static bool is_single_gcode_word(const char* c) {
|
||||
c = skip_word(c);
|
||||
c = skip_whitespaces(c);
|
||||
return is_end_of_gcode_line(*c);
|
||||
}
|
||||
static bool starts_with(const std::string &comment, const std::string &tag) {
|
||||
size_t tag_len = tag.size();
|
||||
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
|
||||
}
|
||||
static ExtrusionRole string_to_role(const std::string& role);
|
||||
//BBS: Returns true if the number was parsed correctly into out and the number spanned the whole input string.
|
||||
static bool parse_double_from_str(const std::string& input, double& out) {
|
||||
size_t read = 0;
|
||||
try {
|
||||
out = std::stod(input, &read);
|
||||
return input.size() == read;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EPositioningType m_global_positioning_type = EPositioningType::Absolute;
|
||||
EPositioningType m_e_local_positioning_type = EPositioningType::Absolute;
|
||||
|
||||
std::array<double, 4> m_start_position = { 0.0, 0.0, 0.0, 0.0 };
|
||||
std::array<double, 4> m_end_position = { 0.0, 0.0, 0.0, 0.0 };
|
||||
std::array<double, 4> m_origin = { 0.0, 0.0, 0.0, 0.0 };
|
||||
|
||||
//BBS: use these value to save information from comment
|
||||
ExtrusionRole m_role = erNone;
|
||||
bool m_wiping = false;
|
||||
int m_layer_num = 0;
|
||||
double m_height = 0.0;
|
||||
double m_width = 0.0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
24
bbs_test_tools/bbs_gcode_checker/main.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "GCodeChecker.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace BambuStudio;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
cout << "Invalid input arguments" << endl;
|
||||
return -1;
|
||||
}
|
||||
string path(argv[1]);
|
||||
cout << "Start to check file " << path << endl;
|
||||
GCodeChecker checker;
|
||||
|
||||
//BBS: parse and check whether has invalid gcode
|
||||
if (checker.parse_file(path) != GCodeCheckResult::Success) {
|
||||
cout << "Failed to parse and check file " << path << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cout << "Success to parse and check file" << path << endl;
|
||||
return 0;
|
||||
}
|
||||
377
build_flatpak.sh
@@ -1,377 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# OrcaSlicer Flatpak Build Script
|
||||
# This script builds and packages OrcaSlicer as a Flatpak package locally
|
||||
# Based on the GitHub Actions workflow in .github/workflows/build_all.yml
|
||||
|
||||
set -e
|
||||
SECONDS=0
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
ARCH=$(uname -m)
|
||||
BUILD_DIR="build_flatpak"
|
||||
CLEANUP=false
|
||||
INSTALL_RUNTIME=false
|
||||
JOBS=$(nproc)
|
||||
FORCE_CLEAN=false
|
||||
ENABLE_CCACHE=false
|
||||
DISABLE_ROFILES_FUSE=false
|
||||
NO_DEBUGINFO=true
|
||||
CACHE_DIR=".flatpak-builder"
|
||||
|
||||
# Help function
|
||||
show_help() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Build OrcaSlicer as a Flatpak package"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -a, --arch ARCH Target architecture (x86_64, aarch64) [default: $ARCH]"
|
||||
echo " -d, --build-dir DIR Build directory [default: $BUILD_DIR]"
|
||||
echo " -j, --jobs JOBS Number of parallel build jobs for flatpak-builder and modules [default: $JOBS]"
|
||||
echo " -c, --cleanup Clean build directory before building"
|
||||
echo " -f, --force-clean Force clean build (disables caching)"
|
||||
echo " --ccache Enable ccache for faster rebuilds (requires ccache in SDK)"
|
||||
echo " --disable-rofiles-fuse Disable rofiles-fuse (workaround for FUSE issues)"
|
||||
echo " --with-debuginfo Include debug info (slower builds, needed for Flathub)"
|
||||
echo " --cache-dir DIR Flatpak builder cache directory [default: $CACHE_DIR]"
|
||||
echo " -i, --install-runtime Install required Flatpak runtime and SDK"
|
||||
echo " -h, --help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Build for current architecture with caching enabled"
|
||||
echo " $0 -f # Force clean build (no caching)"
|
||||
echo " $0 --ccache -j 8 # Use ccache and 8 parallel jobs for faster builds"
|
||||
echo " $0 -a x86_64 -c # Build for x86_64 and cleanup first"
|
||||
echo " $0 -i -j 16 --ccache # Install runtime, build with 16 jobs and ccache"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-a|--arch)
|
||||
ARCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d|--build-dir)
|
||||
BUILD_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-j|--jobs)
|
||||
JOBS="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c|--cleanup)
|
||||
CLEANUP=true
|
||||
shift
|
||||
;;
|
||||
-f|--force-clean)
|
||||
FORCE_CLEAN=true
|
||||
shift
|
||||
;;
|
||||
--ccache)
|
||||
ENABLE_CCACHE=true
|
||||
shift
|
||||
;;
|
||||
--disable-rofiles-fuse)
|
||||
DISABLE_ROFILES_FUSE=true
|
||||
shift
|
||||
;;
|
||||
--with-debuginfo)
|
||||
NO_DEBUGINFO=false
|
||||
shift
|
||||
;;
|
||||
--cache-dir)
|
||||
CACHE_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-i|--install-runtime)
|
||||
INSTALL_RUNTIME=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Error: Unknown option $1${NC}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate architecture
|
||||
if [[ "$ARCH" != "x86_64" && "$ARCH" != "aarch64" ]]; then
|
||||
echo -e "${RED}Error: Unsupported architecture '$ARCH'. Supported: x86_64, aarch64${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate jobs parameter
|
||||
if ! [[ "$JOBS" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo -e "${RED}Error: Jobs must be a positive integer, got '$JOBS'${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}OrcaSlicer Flatpak Build Script${NC}"
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo -e "Architecture: ${GREEN}$ARCH${NC}"
|
||||
echo -e "Build directory: ${GREEN}$BUILD_DIR${NC}"
|
||||
echo -e "Cache directory: ${GREEN}$CACHE_DIR${NC}"
|
||||
echo -e "Parallel jobs: ${GREEN}$JOBS${NC}"
|
||||
if [[ "$FORCE_CLEAN" == true ]]; then
|
||||
echo -e "Cache mode: ${RED}DISABLED (force clean)${NC}"
|
||||
else
|
||||
echo -e "Cache mode: ${GREEN}ENABLED${NC}"
|
||||
fi
|
||||
if [[ "$ENABLE_CCACHE" == true ]]; then
|
||||
echo -e "Ccache: ${GREEN}ENABLED${NC}"
|
||||
else
|
||||
echo -e "Ccache: ${YELLOW}DISABLED${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Check available disk space (flatpak builds need several GB)
|
||||
AVAILABLE_SPACE=$(df . | awk 'NR==2 {print $4}')
|
||||
REQUIRED_SPACE=$((5 * 1024 * 1024)) # 5GB in KB
|
||||
|
||||
if [[ $AVAILABLE_SPACE -lt $REQUIRED_SPACE ]]; then
|
||||
echo -e "${YELLOW}Warning: Low disk space detected.${NC}"
|
||||
echo -e "Available: $(( AVAILABLE_SPACE / 1024 / 1024 ))GB, Recommended: 5GB+"
|
||||
echo -e "Continue anyway? (y/N)"
|
||||
read -r response
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
echo "Build cancelled by user"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if flatpak is installed
|
||||
if ! command -v flatpak &> /dev/null; then
|
||||
echo -e "${RED}Error: Flatpak is not installed. Please install it first.${NC}"
|
||||
echo "On Ubuntu/Debian: sudo apt install flatpak"
|
||||
echo "On Fedora: sudo dnf install flatpak"
|
||||
echo "On Arch: sudo pacman -S flatpak"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if flatpak-builder is installed
|
||||
if ! command -v flatpak-builder &> /dev/null; then
|
||||
echo -e "${RED}Error: flatpak-builder is not installed. Please install it first.${NC}"
|
||||
echo "On Ubuntu/Debian: sudo apt install flatpak-builder"
|
||||
echo "On Fedora: sudo dnf install flatpak-builder"
|
||||
echo "On Arch: sudo pacman -S flatpak-builder"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check additional build dependencies
|
||||
echo -e "${YELLOW}Checking build dependencies...${NC}"
|
||||
MISSING_DEPS=()
|
||||
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
MISSING_DEPS+=("cmake")
|
||||
fi
|
||||
|
||||
if ! command -v ninja &> /dev/null && ! command -v make &> /dev/null; then
|
||||
MISSING_DEPS+=("ninja or make")
|
||||
fi
|
||||
|
||||
if ! command -v pkg-config &> /dev/null; then
|
||||
MISSING_DEPS+=("pkg-config")
|
||||
fi
|
||||
|
||||
if [ ${#MISSING_DEPS[@]} -ne 0 ]; then
|
||||
echo -e "${RED}Error: Missing required build dependencies: ${MISSING_DEPS[*]}${NC}"
|
||||
echo "On Ubuntu/Debian: sudo apt install cmake ninja-build pkg-config"
|
||||
echo "On Fedora: sudo dnf install cmake ninja-build pkgconfig"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}All required dependencies found${NC}"
|
||||
|
||||
# Install runtime and SDK if requested
|
||||
if [[ "$INSTALL_RUNTIME" == true ]]; then
|
||||
echo -e "${YELLOW}Installing GNOME runtime and SDK...${NC}"
|
||||
flatpak install --user -y flathub org.gnome.Platform//50
|
||||
flatpak install --user -y flathub org.gnome.Sdk//50
|
||||
fi
|
||||
|
||||
# Check if required runtime is available
|
||||
if ! flatpak info --user org.gnome.Platform//50 &> /dev/null; then
|
||||
echo -e "${RED}Error: GNOME Platform 50 runtime is not installed.${NC}"
|
||||
echo "Run with -i flag to install it automatically, or install manually:"
|
||||
echo "flatpak install --user flathub org.gnome.Platform//50"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! flatpak info --user org.gnome.Sdk//50 &> /dev/null; then
|
||||
echo -e "${RED}Error: GNOME SDK 50 is not installed.${NC}"
|
||||
echo "Run with -i flag to install it automatically, or install manually:"
|
||||
echo "flatpak install --user flathub org.gnome.Sdk//50"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get version information
|
||||
echo -e "${YELLOW}Getting version information...${NC}"
|
||||
if [[ -f "version.inc" ]]; then
|
||||
VER_PURE=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
||||
VER="V$VER_PURE"
|
||||
DATE=$(date +'%Y%m%d')
|
||||
echo -e "Version: ${GREEN}$VER${NC}"
|
||||
echo -e "Date: ${GREEN}$DATE${NC}"
|
||||
else
|
||||
echo -e "${RED}Error: version.inc not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup build directory if requested
|
||||
if [[ "$CLEANUP" == true ]]; then
|
||||
echo -e "${YELLOW}Cleaning up flatpak-specific build directories...${NC}"
|
||||
rm -rf deps/build_flatpak build_flatpak
|
||||
|
||||
echo -e "${YELLOW}Cleaning up flatpak build directories...${NC}"
|
||||
rm -rf "$BUILD_DIR"
|
||||
|
||||
# Only clean cache if force-clean is enabled
|
||||
if [[ "$FORCE_CLEAN" == true ]]; then
|
||||
echo -e "${YELLOW}Cleaning up flatpak build cache...${NC}"
|
||||
rm -rf "$CACHE_DIR"
|
||||
else
|
||||
echo -e "${BLUE}Preserving build cache at: $CACHE_DIR${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Note: Host build directories (deps/build, build) are preserved${NC}"
|
||||
fi
|
||||
|
||||
# Create build directory
|
||||
mkdir -p "$BUILD_DIR"
|
||||
rm -rf "$BUILD_DIR/build-dir"
|
||||
|
||||
# Check if flatpak manifest exists
|
||||
if [[ ! -f "./scripts/flatpak/com.orcaslicer.OrcaSlicer.yml" ]]; then
|
||||
echo -e "${RED}Error: Flatpak manifest not found at scripts/flatpak/com.orcaslicer.OrcaSlicer.yml${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the Flatpak
|
||||
echo -e "${YELLOW}Building Flatpak package...${NC}"
|
||||
echo -e "This may take a while (30+ minutes depending on your system)..."
|
||||
echo ""
|
||||
|
||||
BUNDLE_NAME="OrcaSlicer-Linux-flatpak_${VER}_${ARCH}.flatpak"
|
||||
|
||||
# Remove any existing bundle
|
||||
rm -f "$BUNDLE_NAME"
|
||||
|
||||
# Create necessary directories inside repo
|
||||
mkdir -p "$BUILD_DIR/cache" "$BUILD_DIR/flatpak-builder"
|
||||
|
||||
# Set environment variables to match GitHub Actions
|
||||
export FLATPAK_BUILDER_N_JOBS=$JOBS
|
||||
|
||||
echo -e "${BLUE}Running flatpak-builder...${NC}"
|
||||
echo -e "Using $JOBS parallel jobs for flatpak-builder and $FLATPAK_BUILDER_N_JOBS for module builds"
|
||||
|
||||
# Check flatpak-builder version to determine available options
|
||||
FLATPAK_BUILDER_VERSION=$(flatpak-builder --version 2>/dev/null | head -1 | awk '{print $2}' || echo "unknown")
|
||||
echo -e "flatpak-builder version: $FLATPAK_BUILDER_VERSION"
|
||||
|
||||
# Build command with caching support
|
||||
BUILDER_ARGS=(
|
||||
--arch="$ARCH"
|
||||
--user
|
||||
--install-deps-from=flathub
|
||||
--repo="$BUILD_DIR/repo"
|
||||
--verbose
|
||||
--state-dir="$CACHE_DIR"
|
||||
--jobs="$JOBS"
|
||||
--mirror-screenshots-url=https://dl.flathub.org/media/
|
||||
)
|
||||
|
||||
# Add force-clean only if explicitly requested (disables caching)
|
||||
if [[ "$FORCE_CLEAN" == true ]]; then
|
||||
BUILDER_ARGS+=(--force-clean)
|
||||
echo -e "${YELLOW}Using --force-clean (caching disabled)${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Using build cache for faster rebuilds${NC}"
|
||||
fi
|
||||
|
||||
# Add ccache if enabled
|
||||
if [[ "$ENABLE_CCACHE" == true ]]; then
|
||||
BUILDER_ARGS+=(--ccache)
|
||||
echo -e "${GREEN}Using ccache for compiler caching${NC}"
|
||||
fi
|
||||
|
||||
# Disable rofiles-fuse if requested (workaround for FUSE issues)
|
||||
if [[ "$DISABLE_ROFILES_FUSE" == true ]]; then
|
||||
BUILDER_ARGS+=(--disable-rofiles-fuse)
|
||||
echo -e "${YELLOW}rofiles-fuse disabled${NC}"
|
||||
fi
|
||||
|
||||
# Use a temp manifest with no-debuginfo if requested
|
||||
MANIFEST="scripts/flatpak/com.orcaslicer.OrcaSlicer.yml"
|
||||
if [[ "$NO_DEBUGINFO" == true ]]; then
|
||||
MANIFEST="scripts/flatpak/com.orcaslicer.OrcaSlicer.no-debug.yml"
|
||||
sed '/^build-options:/a\ no-debuginfo: true\n strip: true' \
|
||||
scripts/flatpak/com.orcaslicer.OrcaSlicer.yml > "$MANIFEST"
|
||||
echo -e "${YELLOW}Debug info disabled (using temp manifest)${NC}"
|
||||
fi
|
||||
|
||||
if ! flatpak-builder \
|
||||
"${BUILDER_ARGS[@]}" \
|
||||
"$BUILD_DIR/build-dir" \
|
||||
"$MANIFEST"; then
|
||||
echo -e "${RED}Error: flatpak-builder failed${NC}"
|
||||
echo -e "${YELLOW}Check the build log above for details${NC}"
|
||||
rm -f "scripts/flatpak/com.orcaslicer.OrcaSlicer.no-debug.yml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up temp manifest
|
||||
rm -f "scripts/flatpak/com.orcaslicer.OrcaSlicer.no-debug.yml"
|
||||
|
||||
# Create bundle
|
||||
echo -e "${YELLOW}Creating Flatpak bundle...${NC}"
|
||||
if ! flatpak build-bundle \
|
||||
"$BUILD_DIR/repo" \
|
||||
"$BUNDLE_NAME" \
|
||||
com.orcaslicer.OrcaSlicer \
|
||||
--arch="$ARCH"; then
|
||||
echo -e "${RED}Error: Failed to create Flatpak bundle${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Success message
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ Flatpak build completed successfully!${NC}"
|
||||
echo -e "Bundle created: ${GREEN}$BUNDLE_NAME${NC}"
|
||||
echo -e "Size: ${GREEN}$(du -h "$BUNDLE_NAME" | cut -f1)${NC}"
|
||||
if [[ "$FORCE_CLEAN" != true ]]; then
|
||||
echo -e "Build cache: ${GREEN}$CACHE_DIR${NC} (preserved for faster future builds)"
|
||||
fi
|
||||
echo ""
|
||||
echo -e "${BLUE}To install the Flatpak:${NC}"
|
||||
echo -e "flatpak install --user $BUNDLE_NAME"
|
||||
echo ""
|
||||
echo -e "${BLUE}To run OrcaSlicer:${NC}"
|
||||
echo -e "flatpak run com.orcaslicer.OrcaSlicer"
|
||||
echo ""
|
||||
echo -e "${BLUE}To uninstall:${NC}"
|
||||
echo -e "flatpak uninstall --user com.orcaslicer.OrcaSlicer"
|
||||
echo ""
|
||||
if [[ "$FORCE_CLEAN" != true ]]; then
|
||||
echo -e "${BLUE}Cache Management:${NC}"
|
||||
echo -e "• Subsequent builds will be faster thanks to caching"
|
||||
echo -e "• To force a clean build: $0 -f"
|
||||
echo -e "• To clean cache manually: rm -rf $CACHE_DIR"
|
||||
fi
|
||||
|
||||
elapsed=$SECONDS
|
||||
printf "\nBuild completed in %dh %dm %ds\n" $((elapsed/3600)) $((elapsed%3600/60)) $((elapsed%60))
|
||||
597
build_linux.sh
@@ -1,597 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e # Exit immediately if a command exits with a non-zero status.
|
||||
SECONDS=0
|
||||
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
SCRIPT_PATH=$(dirname "$(readlink -f "${0}")")
|
||||
|
||||
pushd "${SCRIPT_PATH}" > /dev/null
|
||||
|
||||
function usage() {
|
||||
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-p][-r][-s][-t][-u][-l][-L]"
|
||||
echo " -1: limit builds to one core (where possible)"
|
||||
echo " -j N: limit builds to N cores (where possible)"
|
||||
echo " -b: build in Debug mode"
|
||||
echo " -c: force a clean build"
|
||||
echo " -C: enable ANSI-colored compile output (GNU/Clang only)"
|
||||
echo " -d: download and build dependencies in ./deps/ (build prerequisite)"
|
||||
echo " -D: dry run"
|
||||
echo " -e: build in RelWithDebInfo mode"
|
||||
echo " -F: rebuild the cached Docker/Podman runner image from scratch when used with -g"
|
||||
echo " -g: run the requested build steps inside a Docker/Podman Ubuntu 24.04 container similar to the GitHub Actions Linux runner"
|
||||
echo " -h: prints this help text"
|
||||
echo " -i: build the Orca Slicer AppImage (optional)"
|
||||
echo " -p: boost ccache hit rate by disabling precompiled headers (default: ON)"
|
||||
echo " -r: skip RAM and disk checks (low RAM compiling)"
|
||||
echo " -s: build the Orca Slicer (optional)"
|
||||
echo " -t: build tests (optional), requires -s flag"
|
||||
echo " -u: install system dependencies (asks for sudo password; build prerequisite)"
|
||||
echo " -l: use Clang instead of GCC (default: GCC)"
|
||||
echo " -L: use ld.lld as linker (if available)"
|
||||
echo "For a first use, you want to './${SCRIPT_NAME} -u'"
|
||||
echo " and then './${SCRIPT_NAME} -dsi'"
|
||||
echo "For a GitHub Actions-like Linux build locally, use './${SCRIPT_NAME} -g -istrlL'"
|
||||
echo "Use './${SCRIPT_NAME} -gF -istrlL' to rebuild the cached runner image first."
|
||||
echo "Set ORCA_CONTAINER_CLI, ORCA_DOCKER_IMAGE, ORCA_DOCKER_BASE_IMAGE, or ORCA_DOCKER_CMAKE_VERSION to override the container runtime, cached image tag, base image, or CMake version."
|
||||
}
|
||||
|
||||
SLIC3R_PRECOMPILED_HEADERS="ON"
|
||||
|
||||
unset name
|
||||
BUILD_DIR=build
|
||||
BUILD_CONFIG=Release
|
||||
FORWARDED_ARGS=()
|
||||
while getopts ":1j:bcCdDeFghiprstulL" opt ; do
|
||||
case ${opt} in
|
||||
1 )
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=1
|
||||
FORWARDED_ARGS+=("-1")
|
||||
;;
|
||||
j )
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
|
||||
FORWARDED_ARGS+=("-j" "$OPTARG")
|
||||
;;
|
||||
b )
|
||||
BUILD_DIR=build-dbg
|
||||
BUILD_CONFIG=Debug
|
||||
FORWARDED_ARGS+=("-b")
|
||||
;;
|
||||
c )
|
||||
CLEAN_BUILD=1
|
||||
FORWARDED_ARGS+=("-c")
|
||||
;;
|
||||
C )
|
||||
COLORED_OUTPUT="-DCOLORED_OUTPUT=ON"
|
||||
FORWARDED_ARGS+=("-C")
|
||||
;;
|
||||
d )
|
||||
BUILD_DEPS="1"
|
||||
FORWARDED_ARGS+=("-d")
|
||||
;;
|
||||
D )
|
||||
DRY_RUN="1"
|
||||
FORWARDED_ARGS+=("-D")
|
||||
;;
|
||||
e )
|
||||
BUILD_DIR=build-dbginfo
|
||||
BUILD_CONFIG=RelWithDebInfo
|
||||
FORWARDED_ARGS+=("-e")
|
||||
;;
|
||||
F )
|
||||
CLEAN_DOCKER_IMAGE="1"
|
||||
;;
|
||||
g )
|
||||
USE_DOCKER="1"
|
||||
;;
|
||||
h ) usage
|
||||
exit 1
|
||||
;;
|
||||
i )
|
||||
BUILD_IMAGE="1"
|
||||
FORWARDED_ARGS+=("-i")
|
||||
;;
|
||||
p )
|
||||
SLIC3R_PRECOMPILED_HEADERS="OFF"
|
||||
FORWARDED_ARGS+=("-p")
|
||||
;;
|
||||
r )
|
||||
SKIP_RAM_CHECK="1"
|
||||
FORWARDED_ARGS+=("-r")
|
||||
;;
|
||||
s )
|
||||
BUILD_ORCA="1"
|
||||
FORWARDED_ARGS+=("-s")
|
||||
;;
|
||||
t )
|
||||
BUILD_TESTS="1"
|
||||
FORWARDED_ARGS+=("-t")
|
||||
;;
|
||||
u )
|
||||
export UPDATE_LIB="1"
|
||||
FORWARDED_ARGS+=("-u")
|
||||
;;
|
||||
l )
|
||||
USE_CLANG="1"
|
||||
FORWARDED_ARGS+=("-l")
|
||||
;;
|
||||
L )
|
||||
USE_LLD="1"
|
||||
FORWARDED_ARGS+=("-L")
|
||||
;;
|
||||
* )
|
||||
echo "Unknown argument '${opt}', aborting."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${OPTIND} -eq 1 ] ; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${CLEAN_DOCKER_IMAGE}" ]] && [[ -z "${USE_DOCKER}" ]] ; then
|
||||
echo "Error: -F requires -g."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function check_available_memory_and_disk() {
|
||||
FREE_MEM_GB=$(free --gibi --total | grep 'Mem' | rev | cut --delimiter=" " --fields=1 | rev)
|
||||
MIN_MEM_GB=10
|
||||
|
||||
FREE_DISK_KB=$(df --block-size=1K . | tail -1 | awk '{print $4}')
|
||||
MIN_DISK_KB=$((10 * 1024 * 1024))
|
||||
|
||||
if [[ ${FREE_MEM_GB} -le ${MIN_MEM_GB} ]] ; then
|
||||
echo -e "\nERROR: Orca Slicer Builder requires at least ${MIN_MEM_GB}G of 'available' mem (system has only ${FREE_MEM_GB}G available)"
|
||||
echo && free --human && echo
|
||||
echo "Invoke with -r to skip RAM and disk checks."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ${FREE_DISK_KB} -le ${MIN_DISK_KB} ]] ; then
|
||||
echo -e "\nERROR: Orca Slicer Builder requires at least $(echo "${MIN_DISK_KB}" |awk '{ printf "%.1fG\n", $1/1024/1024; }') (system has only $(echo "${FREE_DISK_KB}" | awk '{ printf "%.1fG\n", $1/1024/1024; }') disk free)"
|
||||
echo && df --human-readable . && echo
|
||||
echo "Invoke with -r to skip ram and disk checks."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function print_and_run() {
|
||||
cmd=()
|
||||
# Remove empty arguments, leading and trailing spaces
|
||||
for item in "$@" ; do
|
||||
if [[ -n $item ]]; then
|
||||
cmd+=( "$(echo "${item}" | xargs)" )
|
||||
fi
|
||||
done
|
||||
|
||||
echo "${cmd[@]}"
|
||||
if [[ -z "${DRY_RUN}" ]] ; then
|
||||
"${cmd[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
function resolve_container_cli() {
|
||||
if [[ -n "${ORCA_CONTAINER_CLI}" ]] ; then
|
||||
if ! command -v "${ORCA_CONTAINER_CLI}" >/dev/null 2>&1 ; then
|
||||
echo "Error: container runtime '${ORCA_CONTAINER_CLI}' was not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "${ORCA_CONTAINER_CLI}"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v docker >/dev/null 2>&1 ; then
|
||||
echo "docker"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v podman >/dev/null 2>&1 ; then
|
||||
echo "podman"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Error: neither docker nor podman is available. Install one of them or set ORCA_CONTAINER_CLI." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function get_docker_runner_image() {
|
||||
local base_image
|
||||
local docker_cmake_version
|
||||
local recipe_hash
|
||||
local sanitized_base_image
|
||||
local sanitized_cmake_version
|
||||
|
||||
if [[ -n "${ORCA_DOCKER_IMAGE}" ]] ; then
|
||||
echo "${ORCA_DOCKER_IMAGE}"
|
||||
return
|
||||
fi
|
||||
|
||||
base_image="${ORCA_DOCKER_BASE_IMAGE:-ubuntu:24.04}"
|
||||
docker_cmake_version="${ORCA_DOCKER_CMAKE_VERSION-4.3.0}"
|
||||
recipe_hash=$(find "${SCRIPT_PATH}/build_linux.sh" "${SCRIPT_PATH}/scripts/linux.d" -type f -print0 | sort -z | xargs -0 cat | sha256sum | cut -c1-12)
|
||||
sanitized_base_image=$(echo "${base_image}" | tr '/:@' '---' | tr -cs 'A-Za-z0-9_.-' '-')
|
||||
sanitized_cmake_version=$(echo "${docker_cmake_version:-system}" | tr -cs 'A-Za-z0-9_.-' '-')
|
||||
echo "orcaslicer-linux-builder:${sanitized_base_image}-cmake-${sanitized_cmake_version}-${recipe_hash}"
|
||||
}
|
||||
|
||||
function docker_runner_dockerfile() {
|
||||
cat <<'EOF'
|
||||
ARG BASE_IMAGE=ubuntu:24.04
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
ARG CMAKE_VERSION=4.3.0
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
RUN apt-get update && apt-get install -y sudo ca-certificates curl tar
|
||||
|
||||
COPY build_linux.sh /tmp/orcaslicer/build_linux.sh
|
||||
COPY scripts/linux.d /tmp/orcaslicer/scripts/linux.d
|
||||
|
||||
WORKDIR /tmp/orcaslicer
|
||||
|
||||
RUN chmod +x ./build_linux.sh
|
||||
RUN ./build_linux.sh -ur
|
||||
RUN if [[ -n "${CMAKE_VERSION}" ]] ; then \
|
||||
case "$(uname -m)" in \
|
||||
x86_64|amd64) cmake_arch="x86_64" ;; \
|
||||
aarch64|arm64) cmake_arch="aarch64" ;; \
|
||||
*) cmake_arch="" ;; \
|
||||
esac ; \
|
||||
if [[ -n "${cmake_arch}" ]] ; then \
|
||||
cmake_root="/opt/cmake-${CMAKE_VERSION}-linux-${cmake_arch}" ; \
|
||||
if ! curl -fsSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-${cmake_arch}.tar.gz" | tar -xz -C /opt ; then \
|
||||
echo "Warning: failed to install CMake ${CMAKE_VERSION}; falling back to the distro cmake package." ; \
|
||||
elif [[ -d "${cmake_root}" ]] ; then \
|
||||
ln -sf "${cmake_root}/bin/"* /usr/local/bin/ ; \
|
||||
fi ; \
|
||||
else \
|
||||
echo "Skipping GitHub Actions CMake install for unsupported architecture $(uname -m)." ; \
|
||||
fi ; \
|
||||
fi
|
||||
RUN rm -rf /var/lib/apt/lists/* /tmp/orcaslicer
|
||||
EOF
|
||||
}
|
||||
|
||||
function ensure_docker_runner_image() {
|
||||
local container_cli
|
||||
local base_image
|
||||
local runner_image
|
||||
local docker_cmake_version
|
||||
local image_exists="0"
|
||||
local force_rebuild="0"
|
||||
local -a build_cmd
|
||||
|
||||
container_cli="$1"
|
||||
runner_image="$2"
|
||||
base_image="${ORCA_DOCKER_BASE_IMAGE:-ubuntu:24.04}"
|
||||
docker_cmake_version="${ORCA_DOCKER_CMAKE_VERSION-4.3.0}"
|
||||
|
||||
if "${container_cli}" image inspect "${runner_image}" >/dev/null 2>&1 ; then
|
||||
image_exists="1"
|
||||
fi
|
||||
|
||||
if [[ -n "${CLEAN_DOCKER_IMAGE}" ]] ; then
|
||||
force_rebuild="1"
|
||||
if [[ "${image_exists}" == "1" ]] ; then
|
||||
echo "Removing cached container image ${runner_image} ..."
|
||||
if [[ -z "${DRY_RUN}" ]] ; then
|
||||
"${container_cli}" image rm -f "${runner_image}" >/dev/null
|
||||
else
|
||||
printf '%q ' "${container_cli}" image rm -f "${runner_image}"
|
||||
echo
|
||||
fi
|
||||
image_exists="0"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${image_exists}" == "1" ]] ; then
|
||||
echo "Using cached container image ${runner_image}"
|
||||
return
|
||||
fi
|
||||
|
||||
build_cmd=(
|
||||
"${container_cli}" build --pull
|
||||
-t "${runner_image}"
|
||||
--build-arg "BASE_IMAGE=${base_image}"
|
||||
--build-arg "CMAKE_VERSION=${docker_cmake_version}"
|
||||
)
|
||||
if [[ "${force_rebuild}" == "1" ]] ; then
|
||||
build_cmd+=(--no-cache)
|
||||
fi
|
||||
build_cmd+=(-f - "${SCRIPT_PATH}")
|
||||
|
||||
printf '%q ' "${build_cmd[@]}"
|
||||
echo
|
||||
if [[ -n "${DRY_RUN}" ]] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
docker_runner_dockerfile | "${build_cmd[@]}"
|
||||
}
|
||||
|
||||
function run_in_docker() {
|
||||
local container_cli
|
||||
local runner_image
|
||||
local container_workspace
|
||||
local host_uid
|
||||
local host_gid
|
||||
local host_user
|
||||
local -a build_args
|
||||
local -a container_env
|
||||
|
||||
container_cli=$(resolve_container_cli)
|
||||
runner_image=$(get_docker_runner_image)
|
||||
host_uid=$(id -u)
|
||||
host_gid=$(id -g)
|
||||
host_user="${USER:-orca}"
|
||||
container_workspace="/__w/OrcaSlicer/OrcaSlicer"
|
||||
build_args=()
|
||||
for item in "${FORWARDED_ARGS[@]}" ; do
|
||||
if [[ "${item}" == "-u" ]] || [[ "${item}" == "-D" ]] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
build_args+=("${item}")
|
||||
done
|
||||
|
||||
container_env=(
|
||||
-e "CI=true"
|
||||
-e "GITHUB_ACTIONS=true"
|
||||
-e "GITHUB_WORKSPACE=${container_workspace}"
|
||||
-e "RUNNER_OS=Linux"
|
||||
-e "RUNNER_TEMP=/tmp"
|
||||
-e "HOST_UID=${host_uid}"
|
||||
-e "HOST_GID=${host_gid}"
|
||||
-e "HOST_USER=${host_user}"
|
||||
)
|
||||
if [[ -n "${CMAKE_BUILD_PARALLEL_LEVEL}" ]] ; then
|
||||
container_env+=( -e "CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL}" )
|
||||
fi
|
||||
if [[ -n "${ORCA_UPDATER_SIG_KEY}" ]] ; then
|
||||
container_env+=( -e "ORCA_UPDATER_SIG_KEY=${ORCA_UPDATER_SIG_KEY}" )
|
||||
fi
|
||||
|
||||
ensure_docker_runner_image "${container_cli}" "${runner_image}"
|
||||
|
||||
printf '%q ' "${container_cli}" run --rm -i \
|
||||
-v "${SCRIPT_PATH}:${container_workspace}" \
|
||||
-w "${container_workspace}" \
|
||||
"${container_env[@]}" \
|
||||
"${runner_image}" \
|
||||
bash -s -- "${build_args[@]}"
|
||||
echo
|
||||
if [[ -n "${DRY_RUN}" ]] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
"${container_cli}" run --rm -i \
|
||||
-v "${SCRIPT_PATH}:${container_workspace}" \
|
||||
-w "${container_workspace}" \
|
||||
"${container_env[@]}" \
|
||||
"${runner_image}" \
|
||||
bash -s -- "${build_args[@]}" <<'EOF'
|
||||
set -e
|
||||
|
||||
function create_builder_user() {
|
||||
if [[ "${HOST_UID}" == "0" ]] ; then
|
||||
HOST_USER=root
|
||||
return
|
||||
fi
|
||||
|
||||
if getent group "${HOST_GID}" >/dev/null 2>&1 ; then
|
||||
HOST_GROUP=$(getent group "${HOST_GID}" | cut -d: -f1)
|
||||
else
|
||||
HOST_GROUP="orca-builder"
|
||||
if getent group "${HOST_GROUP}" >/dev/null 2>&1 ; then
|
||||
HOST_GROUP="orca-builder-${HOST_GID}"
|
||||
fi
|
||||
groupadd -g "${HOST_GID}" "${HOST_GROUP}"
|
||||
fi
|
||||
|
||||
if getent passwd "${HOST_UID}" >/dev/null 2>&1 ; then
|
||||
HOST_USER=$(getent passwd "${HOST_UID}" | cut -d: -f1)
|
||||
usermod -g "${HOST_GROUP}" "${HOST_USER}"
|
||||
elif id -u "${HOST_USER}" >/dev/null 2>&1 ; then
|
||||
usermod -u "${HOST_UID}" -g "${HOST_GROUP}" "${HOST_USER}"
|
||||
else
|
||||
useradd -m -u "${HOST_UID}" -g "${HOST_GROUP}" -s /bin/bash "${HOST_USER}"
|
||||
fi
|
||||
|
||||
echo "${HOST_USER} ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/orcaslicer-builder
|
||||
chmod 0440 /etc/sudoers.d/orcaslicer-builder
|
||||
}
|
||||
|
||||
create_builder_user
|
||||
mkdir -p "${GITHUB_WORKSPACE}/deps/build/destdir"
|
||||
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/deps/build"
|
||||
if [[ -d "${GITHUB_WORKSPACE}/build" ]] ; then
|
||||
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build"
|
||||
fi
|
||||
if [[ -d "${GITHUB_WORKSPACE}/build-dbg" ]] ; then
|
||||
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build-dbg"
|
||||
fi
|
||||
if [[ -d "${GITHUB_WORKSPACE}/build-dbginfo" ]] ; then
|
||||
chown -R "${HOST_UID}:${HOST_GID}" "${GITHUB_WORKSPACE}/build-dbginfo"
|
||||
fi
|
||||
|
||||
sudo -H -u "${HOST_USER}" env \
|
||||
CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL-}" \
|
||||
GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" \
|
||||
ORCA_UPDATER_SIG_KEY="${ORCA_UPDATER_SIG_KEY-}" \
|
||||
bash -c '
|
||||
set -e
|
||||
cd "${GITHUB_WORKSPACE}"
|
||||
if [[ "$#" -gt 0 ]] ; then
|
||||
./build_linux.sh "$@"
|
||||
else
|
||||
echo "No build steps were requested after container setup."
|
||||
fi
|
||||
' bash "$@"
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ -n "${USE_DOCKER}" ]] ; then
|
||||
run_in_docker
|
||||
popd > /dev/null # ${SCRIPT_PATH}
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# cmake 4.x compatibility workaround
|
||||
export CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
|
||||
DISTRIBUTION=$(awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"')
|
||||
DISTRIBUTION_LIKE=$(awk -F= '/^ID_LIKE=/ {print $2}' /etc/os-release | tr -d '"')
|
||||
# Check for direct distribution match to Ubuntu/Debian
|
||||
if [ "${DISTRIBUTION}" == "ubuntu" ] || [ "${DISTRIBUTION}" == "linuxmint" ] ; then
|
||||
DISTRIBUTION="debian"
|
||||
# Check if distribution is Debian/Ubuntu-like based on ID_LIKE
|
||||
elif [[ "${DISTRIBUTION_LIKE}" == *"debian"* ]] || [[ "${DISTRIBUTION_LIKE}" == *"ubuntu"* ]] ; then
|
||||
DISTRIBUTION="debian"
|
||||
elif [[ "${DISTRIBUTION_LIKE}" == *"arch"* ]] ; then
|
||||
DISTRIBUTION="arch"
|
||||
elif [[ "${DISTRIBUTION_LIKE}" == *"suse"* ]] ; then
|
||||
DISTRIBUTION="suse"
|
||||
fi
|
||||
|
||||
if [ ! -f "./scripts/linux.d/${DISTRIBUTION}" ] ; then
|
||||
echo "Your distribution \"${DISTRIBUTION}\" is not supported by system-dependency scripts in ./scripts/linux.d/"
|
||||
echo "Please resolve dependencies manually and contribute a script for your distribution to upstream."
|
||||
exit 1
|
||||
else
|
||||
echo "resolving system dependencies for distribution \"${DISTRIBUTION}\" ..."
|
||||
# shellcheck source=/dev/null
|
||||
source "./scripts/linux.d/${DISTRIBUTION}"
|
||||
fi
|
||||
|
||||
echo "FOUND_GTK3_DEV=${FOUND_GTK3_DEV}"
|
||||
if [[ -z "${FOUND_GTK3_DEV}" ]] ; then
|
||||
echo "Error, you must install the dependencies before."
|
||||
echo "Use option -u with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Changing date in version..."
|
||||
{
|
||||
# change date in version
|
||||
sed --in-place "s/+UNKNOWN/_$(date '+%F')/" version.inc
|
||||
}
|
||||
echo "done"
|
||||
|
||||
|
||||
if [[ -z "${SKIP_RAM_CHECK}" ]] ; then
|
||||
check_available_memory_and_disk
|
||||
fi
|
||||
|
||||
export CMAKE_C_CXX_COMPILER_CLANG=()
|
||||
if [[ -n "${USE_CLANG}" ]] ; then
|
||||
export CMAKE_C_CXX_COMPILER_CLANG=(-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++)
|
||||
fi
|
||||
|
||||
# Configure use of ld.lld as the linker when requested
|
||||
export CMAKE_LLD_LINKER_ARGS=()
|
||||
if [[ -n "${USE_LLD}" ]] ; then
|
||||
if command -v ld.lld >/dev/null 2>&1 ; then
|
||||
LLD_BIN=$(command -v ld.lld)
|
||||
export CMAKE_LLD_LINKER_ARGS=(-DCMAKE_LINKER="${LLD_BIN}" -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_MODULE_LINKER_FLAGS=-fuse-ld=lld)
|
||||
else
|
||||
echo "Error: ld.lld not found. Please install the 'lld' package (e.g., sudo apt install lld) or omit -L."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
export CMAKE_CCACHE_ARGS=()
|
||||
CMAKE_CCACHE=${CMAKE_CCACHE:-}
|
||||
if [ -n "$CMAKE_CCACHE" ]; then
|
||||
echo "Checking ${CMAKE_CCACHE} environment variable for compiler cache program..."
|
||||
CMAKE_CCACHE=$(command -v "${CMAKE_CCACHE}") || {
|
||||
echo "CMAKE_CCACHE environment variable is set to '${CMAKE_CCACHE}' but it was not found in PATH."
|
||||
CMAKE_CCACHE=""
|
||||
}
|
||||
elif command -v sccache >/dev/null 2>&1 ; then
|
||||
CMAKE_CCACHE=$(command -v sccache)
|
||||
elif command -v ccache >/dev/null 2>&1 ; then
|
||||
CMAKE_CCACHE=$(command -v ccache)
|
||||
fi
|
||||
if [ -n "${CMAKE_CCACHE}" ] ; then
|
||||
echo "${CMAKE_CCACHE} found, enabling compiler caching..."
|
||||
export CMAKE_CCACHE_ARGS=(-DCMAKE_C_COMPILER_LAUNCHER="${CMAKE_CCACHE}" -DCMAKE_CXX_COMPILER_LAUNCHER="${CMAKE_CCACHE}")
|
||||
else
|
||||
echo "Note: ccache or sccache are not found. Install either of them for faster rebuilds."
|
||||
fi
|
||||
|
||||
if [[ -n "${BUILD_DEPS}" ]] ; then
|
||||
echo "Configuring dependencies..."
|
||||
read -r -a BUILD_ARGS <<< "${DEPS_EXTRA_BUILD_ARGS}"
|
||||
if [[ -n "${CLEAN_BUILD}" ]]
|
||||
then
|
||||
print_and_run rm -fr deps/$BUILD_DIR
|
||||
fi
|
||||
mkdir -p deps/$BUILD_DIR
|
||||
if [[ $BUILD_CONFIG != Release ]] ; then
|
||||
BUILD_ARGS+=(-DCMAKE_BUILD_TYPE="${BUILD_CONFIG}")
|
||||
fi
|
||||
|
||||
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}"
|
||||
print_and_run cmake --build deps/$BUILD_DIR -j1
|
||||
fi
|
||||
|
||||
if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
|
||||
echo "Configuring OrcaSlicer..."
|
||||
if [[ -n "${CLEAN_BUILD}" ]] ; then
|
||||
print_and_run rm -fr $BUILD_DIR
|
||||
fi
|
||||
read -r -a BUILD_ARGS <<< "${ORCA_EXTRA_BUILD_ARGS}"
|
||||
if [[ $BUILD_CONFIG != Release ]] ; then
|
||||
BUILD_ARGS+=(-DCMAKE_BUILD_TYPE="${BUILD_CONFIG}")
|
||||
fi
|
||||
if [[ -n "${BUILD_TESTS}" ]] ; then
|
||||
BUILD_ARGS+=(-DBUILD_TESTS=ON)
|
||||
fi
|
||||
if [[ -n "${ORCA_UPDATER_SIG_KEY}" ]] ; then
|
||||
BUILD_ARGS+=(-DORCA_UPDATER_SIG_KEY="${ORCA_UPDATER_SIG_KEY}")
|
||||
fi
|
||||
|
||||
print_and_run cmake -S . -B $BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G "Ninja Multi-Config" \
|
||||
-DSLIC3R_PCH=${SLIC3R_PRECOMPILED_HEADERS} \
|
||||
-DORCA_TOOLS=ON \
|
||||
"${COLORED_OUTPUT}" \
|
||||
"${BUILD_ARGS[@]}"
|
||||
echo "done"
|
||||
if [[ -n "${BUILD_ORCA}" ]]; then
|
||||
echo "Building OrcaSlicer ..."
|
||||
print_and_run cmake --build $BUILD_DIR --config "${BUILD_CONFIG}" --target OrcaSlicer
|
||||
echo "Building OrcaSlicer_profile_validator .."
|
||||
print_and_run cmake --build $BUILD_DIR --config "${BUILD_CONFIG}" --target OrcaSlicer_profile_validator
|
||||
./scripts/run_gettext.sh
|
||||
fi
|
||||
if [[ -n "${BUILD_TESTS}" ]] ; then
|
||||
echo "Building tests ..."
|
||||
print_and_run cmake --build ${BUILD_DIR} --config "${BUILD_CONFIG}" --target tests/all
|
||||
fi
|
||||
echo "done"
|
||||
fi
|
||||
|
||||
if [[ -n "${BUILD_IMAGE}" || -n "${BUILD_ORCA}" ]] ; then
|
||||
pushd $BUILD_DIR > /dev/null
|
||||
build_linux_image="./src/build_linux_image.sh"
|
||||
if [[ -e ${build_linux_image} ]] ; then
|
||||
extra_script_args=""
|
||||
if [[ -n "${BUILD_IMAGE}" ]] ; then
|
||||
extra_script_args="-i"
|
||||
fi
|
||||
print_and_run ${build_linux_image} ${extra_script_args} -R "${BUILD_CONFIG}"
|
||||
|
||||
echo "done"
|
||||
fi
|
||||
popd > /dev/null # build
|
||||
fi
|
||||
|
||||
elapsed=$SECONDS
|
||||
printf "\nBuild completed in %dh %dm %ds\n" $((elapsed/3600)) $((elapsed%3600/60)) $((elapsed%60))
|
||||
|
||||
popd > /dev/null # ${SCRIPT_PATH}
|
||||
@@ -1,52 +1,14 @@
|
||||
set WP=%CD%
|
||||
|
||||
set debug=OFF
|
||||
set debuginfo=OFF
|
||||
if "%1"=="debug" set debug=ON
|
||||
if "%2"=="debug" set debug=ON
|
||||
if "%1"=="debuginfo" set debuginfo=ON
|
||||
if "%2"=="debuginfo" set debuginfo=ON
|
||||
if "%debug%"=="ON" (
|
||||
set build_type=Debug
|
||||
set build_dir=build-dbg
|
||||
) else (
|
||||
if "%debuginfo%"=="ON" (
|
||||
set build_type=RelWithDebInfo
|
||||
set build_dir=build-dbginfo
|
||||
) else (
|
||||
set build_type=Release
|
||||
set build_dir=build
|
||||
)
|
||||
)
|
||||
echo build type set to %build_type%
|
||||
|
||||
cd deps
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
set DEPS=%CD%/OrcaSlicer_dep
|
||||
set "SIG_FLAG="
|
||||
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
|
||||
if "%1"=="slicer" (
|
||||
GOTO :slicer
|
||||
)
|
||||
echo "building deps.."
|
||||
mkdir build
|
||||
cd build
|
||||
set DEPS=%CD%/BambuStudio_dep
|
||||
cmake ../ -G "Visual Studio 16 2019" -DDESTDIR="%CD%/BambuStudio_dep" -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build . --config Release --target ALL_BUILD -- -m
|
||||
|
||||
echo cmake ../ -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake ../ -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps -- -m
|
||||
|
||||
if "%1"=="deps" exit /b 0
|
||||
|
||||
:slicer
|
||||
echo "building Orca Slicer..."
|
||||
cd %WP%
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
|
||||
echo cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=%build_type% %SIG_FLAG%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
cd ..
|
||||
call scripts/run_gettext.bat
|
||||
cd %build_dir%
|
||||
cmake --build . --target install --config %build_type%
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 16 2019" -DBBL_RELEASE_TO_PUBLIC=0 -DCMAKE_PREFIX_PATH="%DEPS%/usr/local" -DCMAKE_INSTALL_PREFIX="./BambuStudio-SoftFever" -DCMAKE_BUILD_TYPE=Release -DWIN10SDK_PATH="C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0"
|
||||
cmake --build . --config Release --target ALL_BUILD -- -m
|
||||
cmake --build . --target install --config Release
|
||||
@@ -1,348 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
SECONDS=0
|
||||
|
||||
while getopts ":dpa:snt:xbc:i:1Tuh" opt; do
|
||||
case "${opt}" in
|
||||
d )
|
||||
export BUILD_TARGET="deps"
|
||||
;;
|
||||
p )
|
||||
export PACK_DEPS="1"
|
||||
;;
|
||||
a )
|
||||
export ARCH="$OPTARG"
|
||||
;;
|
||||
s )
|
||||
export BUILD_TARGET="slicer"
|
||||
;;
|
||||
n )
|
||||
export NIGHTLY_BUILD="1"
|
||||
;;
|
||||
t )
|
||||
export OSX_DEPLOYMENT_TARGET="$OPTARG"
|
||||
;;
|
||||
x )
|
||||
export SLICER_CMAKE_GENERATOR="Ninja Multi-Config"
|
||||
export SLICER_BUILD_TARGET="all"
|
||||
export DEPS_CMAKE_GENERATOR="Ninja"
|
||||
;;
|
||||
b )
|
||||
export BUILD_ONLY="1"
|
||||
;;
|
||||
c )
|
||||
export BUILD_CONFIG="$OPTARG"
|
||||
;;
|
||||
i )
|
||||
export CMAKE_IGNORE_PREFIX_PATH="${CMAKE_IGNORE_PREFIX_PATH:+$CMAKE_IGNORE_PREFIX_PATH;}$OPTARG"
|
||||
;;
|
||||
1 )
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=1
|
||||
;;
|
||||
T )
|
||||
export BUILD_TESTS="1"
|
||||
;;
|
||||
u )
|
||||
export BUILD_TARGET="universal"
|
||||
;;
|
||||
h ) echo "Usage: ./build_release_macos.sh [-d]"
|
||||
echo " -d: Build deps only"
|
||||
echo " -a: Set ARCHITECTURE (arm64 or x86_64 or universal)"
|
||||
echo " -s: Build slicer only"
|
||||
echo " -u: Build universal app only (requires existing arm64 and x86_64 app bundles)"
|
||||
echo " -n: Nightly build"
|
||||
echo " -t: Specify minimum version of the target platform, default is 11.3"
|
||||
echo " -x: Use Ninja Multi-Config CMake generator, default is Xcode"
|
||||
echo " -b: Build without reconfiguring CMake"
|
||||
echo " -c: Set CMake build configuration, default is Release"
|
||||
echo " -i: Add a prefix to ignore during CMake dependency discovery (repeatable), defaults to /opt/local:/usr/local:/opt/homebrew"
|
||||
echo " -1: Use single job for building"
|
||||
echo " -T: Build and run tests"
|
||||
exit 0
|
||||
;;
|
||||
* )
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Set defaults
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH="$(uname -m)"
|
||||
export ARCH
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_CONFIG" ]; then
|
||||
export BUILD_CONFIG="Release"
|
||||
fi
|
||||
|
||||
if [ -z "$BUILD_TARGET" ]; then
|
||||
export BUILD_TARGET="all"
|
||||
fi
|
||||
|
||||
if [ -z "$SLICER_CMAKE_GENERATOR" ]; then
|
||||
export SLICER_CMAKE_GENERATOR="Xcode"
|
||||
fi
|
||||
|
||||
if [ -z "$SLICER_BUILD_TARGET" ]; then
|
||||
export SLICER_BUILD_TARGET="ALL_BUILD"
|
||||
fi
|
||||
|
||||
if [ -z "$DEPS_CMAKE_GENERATOR" ]; then
|
||||
export DEPS_CMAKE_GENERATOR="Unix Makefiles"
|
||||
fi
|
||||
|
||||
if [ -z "$OSX_DEPLOYMENT_TARGET" ]; then
|
||||
export OSX_DEPLOYMENT_TARGET="11.3"
|
||||
fi
|
||||
|
||||
if [ -z "$CMAKE_IGNORE_PREFIX_PATH" ]; then
|
||||
export CMAKE_IGNORE_PREFIX_PATH="/opt/local:/usr/local:/opt/homebrew"
|
||||
fi
|
||||
|
||||
CMAKE_VERSION=$(cmake --version | head -1 | sed 's/[^0-9]*\([0-9]*\).*/\1/')
|
||||
if [ "$CMAKE_VERSION" -ge 4 ] 2>/dev/null; then
|
||||
export CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
export CMAKE_POLICY_COMPAT="-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
|
||||
echo "Detected CMake 4.x, adding compatibility flag (env + cmake arg)"
|
||||
else
|
||||
export CMAKE_POLICY_COMPAT=""
|
||||
fi
|
||||
|
||||
echo "Build params:"
|
||||
echo " - ARCH: $ARCH"
|
||||
echo " - BUILD_CONFIG: $BUILD_CONFIG"
|
||||
echo " - BUILD_TARGET: $BUILD_TARGET"
|
||||
echo " - CMAKE_GENERATOR: $SLICER_CMAKE_GENERATOR for Slicer, $DEPS_CMAKE_GENERATOR for deps"
|
||||
echo " - OSX_DEPLOYMENT_TARGET: $OSX_DEPLOYMENT_TARGET"
|
||||
echo " - CMAKE_IGNORE_PREFIX_PATH: $CMAKE_IGNORE_PREFIX_PATH"
|
||||
echo
|
||||
|
||||
# if which -s brew; then
|
||||
# brew --prefix libiconv
|
||||
# brew --prefix zstd
|
||||
# export LIBRARY_PATH=$LIBRARY_PATH:$(brew --prefix zstd)/lib/
|
||||
# elif which -s port; then
|
||||
# port install libiconv
|
||||
# port install zstd
|
||||
# export LIBRARY_PATH=$LIBRARY_PATH:/opt/local/lib
|
||||
# else
|
||||
# echo "Need either brew or macports to successfully build deps"
|
||||
# exit 1
|
||||
# fi
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_BUILD_DIR="$PROJECT_DIR/build/$ARCH"
|
||||
DEPS_DIR="$PROJECT_DIR/deps"
|
||||
|
||||
# For Multi-config generators like Ninja and Xcode
|
||||
export BUILD_DIR_CONFIG_SUBDIR="/$BUILD_CONFIG"
|
||||
|
||||
function build_deps() {
|
||||
# iterate over two architectures: x86_64 and arm64
|
||||
for _ARCH in x86_64 arm64; do
|
||||
# if ARCH is universal or equal to _ARCH
|
||||
if [ "$ARCH" == "universal" ] || [ "$ARCH" == "$_ARCH" ]; then
|
||||
|
||||
PROJECT_BUILD_DIR="$PROJECT_DIR/build/$_ARCH"
|
||||
DEPS_BUILD_DIR="$DEPS_DIR/build/$_ARCH"
|
||||
DEPS="$DEPS_BUILD_DIR/OrcaSlicer_dep"
|
||||
|
||||
echo "Building deps..."
|
||||
(
|
||||
set -x
|
||||
mkdir -p "$DEPS"
|
||||
cd "$DEPS_BUILD_DIR"
|
||||
if [ "1." != "$BUILD_ONLY". ]; then
|
||||
cmake "${DEPS_DIR}" \
|
||||
-G "${DEPS_CMAKE_GENERATOR}" \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_CONFIG" \
|
||||
-DCMAKE_OSX_ARCHITECTURES:STRING="${_ARCH}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}" \
|
||||
-DCMAKE_IGNORE_PREFIX_PATH="${CMAKE_IGNORE_PREFIX_PATH}" \
|
||||
${CMAKE_POLICY_COMPAT}
|
||||
fi
|
||||
cmake --build . --config "$BUILD_CONFIG" --target deps
|
||||
)
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function pack_deps() {
|
||||
echo "Packing deps..."
|
||||
(
|
||||
set -x
|
||||
cd "$DEPS_DIR"
|
||||
tar -zcvf "OrcaSlicer_dep_mac_${ARCH}_$(date +"%Y%m%d").tar.gz" "build"
|
||||
)
|
||||
}
|
||||
|
||||
function build_slicer() {
|
||||
# iterate over two architectures: x86_64 and arm64
|
||||
for _ARCH in x86_64 arm64; do
|
||||
# if ARCH is universal or equal to _ARCH
|
||||
if [ "$ARCH" == "universal" ] || [ "$ARCH" == "$_ARCH" ]; then
|
||||
|
||||
PROJECT_BUILD_DIR="$PROJECT_DIR/build/$_ARCH"
|
||||
DEPS_BUILD_DIR="$DEPS_DIR/build/$_ARCH"
|
||||
DEPS="$DEPS_BUILD_DIR/OrcaSlicer_dep"
|
||||
|
||||
echo "Building slicer for $_ARCH..."
|
||||
(
|
||||
set -x
|
||||
mkdir -p "$PROJECT_BUILD_DIR"
|
||||
cd "$PROJECT_BUILD_DIR"
|
||||
if [ "1." != "$BUILD_ONLY". ]; then
|
||||
cmake "${PROJECT_DIR}" \
|
||||
-G "${SLICER_CMAKE_GENERATOR}" \
|
||||
-DORCA_TOOLS=ON \
|
||||
${ORCA_UPDATER_SIG_KEY:+-DORCA_UPDATER_SIG_KEY="$ORCA_UPDATER_SIG_KEY"} \
|
||||
${BUILD_TESTS:+-DBUILD_TESTS=ON} \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_CONFIG" \
|
||||
-DCMAKE_OSX_ARCHITECTURES="${_ARCH}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="${OSX_DEPLOYMENT_TARGET}" \
|
||||
-DCMAKE_IGNORE_PREFIX_PATH="${CMAKE_IGNORE_PREFIX_PATH}" \
|
||||
${CMAKE_POLICY_COMPAT}
|
||||
fi
|
||||
cmake --build . --config "$BUILD_CONFIG" --target "$SLICER_BUILD_TARGET"
|
||||
)
|
||||
|
||||
if [ "1." == "$BUILD_TESTS". ]; then
|
||||
echo "Running tests for $_ARCH..."
|
||||
(
|
||||
set -x
|
||||
cd "$PROJECT_BUILD_DIR"
|
||||
ctest --build-config "$BUILD_CONFIG" --output-on-failure
|
||||
)
|
||||
fi
|
||||
|
||||
echo "Verify localization with gettext..."
|
||||
(
|
||||
cd "$PROJECT_DIR"
|
||||
./scripts/run_gettext.sh
|
||||
)
|
||||
|
||||
echo "Fix macOS app package..."
|
||||
(
|
||||
cd "$PROJECT_BUILD_DIR"
|
||||
mkdir -p OrcaSlicer
|
||||
cd OrcaSlicer
|
||||
# remove previously built app
|
||||
rm -rf ./OrcaSlicer.app
|
||||
# fully copy newly built app
|
||||
cp -pR "../src$BUILD_DIR_CONFIG_SUBDIR/OrcaSlicer.app" ./OrcaSlicer.app
|
||||
# fix resources
|
||||
resources_path=$(readlink ./OrcaSlicer.app/Contents/Resources)
|
||||
rm ./OrcaSlicer.app/Contents/Resources
|
||||
cp -R "$resources_path" ./OrcaSlicer.app/Contents/Resources
|
||||
# delete .DS_Store file
|
||||
find ./OrcaSlicer.app/ -name '.DS_Store' -delete
|
||||
|
||||
# Copy OrcaSlicer_profile_validator.app if it exists
|
||||
if [ -f "../src$BUILD_DIR_CONFIG_SUBDIR/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||
echo "Copying OrcaSlicer_profile_validator.app..."
|
||||
rm -rf ./OrcaSlicer_profile_validator.app
|
||||
cp -pR "../src$BUILD_DIR_CONFIG_SUBDIR/OrcaSlicer_profile_validator.app" ./OrcaSlicer_profile_validator.app
|
||||
# delete .DS_Store file
|
||||
find ./OrcaSlicer_profile_validator.app/ -name '.DS_Store' -delete
|
||||
fi
|
||||
)
|
||||
|
||||
# extract version
|
||||
# export ver=$(grep '^#define SoftFever_VERSION' ../src/libslic3r/libslic3r_version.h | cut -d ' ' -f3)
|
||||
# ver="_V${ver//\"}"
|
||||
# echo $PWD
|
||||
# if [ "1." != "$NIGHTLY_BUILD". ];
|
||||
# then
|
||||
# ver=${ver}_dev
|
||||
# fi
|
||||
|
||||
# zip -FSr OrcaSlicer${ver}_Mac_${_ARCH}.zip OrcaSlicer.app
|
||||
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function lipo_dir() {
|
||||
local universal_dir="$1"
|
||||
local x86_64_dir="$2"
|
||||
|
||||
# Find all Mach-O files in the universal (arm64-based) copy and lipo them
|
||||
while IFS= read -r -d '' f; do
|
||||
local rel="${f#"$universal_dir"/}"
|
||||
local x86="$x86_64_dir/$rel"
|
||||
if [ -f "$x86" ]; then
|
||||
echo " lipo: $rel"
|
||||
lipo -create "$f" "$x86" -output "$f.tmp"
|
||||
mv "$f.tmp" "$f"
|
||||
else
|
||||
echo " warning: no x86_64 counterpart for $rel, keeping arm64 only"
|
||||
fi
|
||||
done < <(find "$universal_dir" -type f -print0 | while IFS= read -r -d '' candidate; do
|
||||
if file "$candidate" | grep -q "Mach-O"; then
|
||||
printf '%s\0' "$candidate"
|
||||
fi
|
||||
done)
|
||||
}
|
||||
|
||||
function build_universal() {
|
||||
echo "Building universal binary..."
|
||||
|
||||
PROJECT_BUILD_DIR="$PROJECT_DIR/build/$ARCH"
|
||||
ARM64_APP="$PROJECT_DIR/build/arm64/OrcaSlicer/OrcaSlicer.app"
|
||||
X86_64_APP="$PROJECT_DIR/build/x86_64/OrcaSlicer/OrcaSlicer.app"
|
||||
|
||||
mkdir -p "$PROJECT_BUILD_DIR/OrcaSlicer"
|
||||
UNIVERSAL_APP="$PROJECT_BUILD_DIR/OrcaSlicer/OrcaSlicer.app"
|
||||
rm -rf "$UNIVERSAL_APP"
|
||||
cp -R "$ARM64_APP" "$UNIVERSAL_APP"
|
||||
|
||||
echo "Creating universal binaries for OrcaSlicer.app..."
|
||||
lipo_dir "$UNIVERSAL_APP" "$X86_64_APP"
|
||||
echo "Universal OrcaSlicer.app created at $UNIVERSAL_APP"
|
||||
|
||||
# Create universal binary for profile validator if it exists
|
||||
ARM64_VALIDATOR="$PROJECT_DIR/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app"
|
||||
X86_64_VALIDATOR="$PROJECT_DIR/build/x86_64/OrcaSlicer/OrcaSlicer_profile_validator.app"
|
||||
if [ -d "$ARM64_VALIDATOR" ] && [ -d "$X86_64_VALIDATOR" ]; then
|
||||
echo "Creating universal binaries for OrcaSlicer_profile_validator.app..."
|
||||
UNIVERSAL_VALIDATOR_APP="$PROJECT_BUILD_DIR/OrcaSlicer/OrcaSlicer_profile_validator.app"
|
||||
rm -rf "$UNIVERSAL_VALIDATOR_APP"
|
||||
cp -R "$ARM64_VALIDATOR" "$UNIVERSAL_VALIDATOR_APP"
|
||||
lipo_dir "$UNIVERSAL_VALIDATOR_APP" "$X86_64_VALIDATOR"
|
||||
echo "Universal OrcaSlicer_profile_validator.app created at $UNIVERSAL_VALIDATOR_APP"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${BUILD_TARGET}" in
|
||||
all)
|
||||
build_deps
|
||||
build_slicer
|
||||
;;
|
||||
deps)
|
||||
build_deps
|
||||
;;
|
||||
slicer)
|
||||
build_slicer
|
||||
;;
|
||||
universal)
|
||||
build_universal
|
||||
;;
|
||||
*)
|
||||
echo "Unknown target: $BUILD_TARGET. Available targets: deps, slicer, universal, all."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$ARCH" = "universal" ] && { [ "$BUILD_TARGET" = "all" ] || [ "$BUILD_TARGET" = "slicer" ]; }; then
|
||||
build_universal
|
||||
fi
|
||||
|
||||
if [ "1." == "$PACK_DEPS". ]; then
|
||||
pack_deps
|
||||
fi
|
||||
|
||||
elapsed=$SECONDS
|
||||
printf "\nBuild completed in %dh %dm %ds\n" $((elapsed/3600)) $((elapsed%3600/60)) $((elapsed%60))
|
||||
@@ -1,171 +0,0 @@
|
||||
@REM OrcaSlicer build script for Windows with VS auto-detect
|
||||
@echo off
|
||||
set WP=%CD%
|
||||
set _START_TIME=%TIME%
|
||||
|
||||
@REM Default target architecture to the host CPU arch; override by passing
|
||||
@REM "x64" or "arm64" as an argument. PROCESSOR_ARCHITEW6432 covers a 32-bit
|
||||
@REM shell running on a 64-bit OS, where PROCESSOR_ARCHITECTURE reads "x86".
|
||||
set arch=x64
|
||||
if /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" set arch=ARM64
|
||||
if /I "%PROCESSOR_ARCHITEW6432%"=="ARM64" set arch=ARM64
|
||||
if /I "%1"=="arm64" set arch=ARM64
|
||||
if /I "%2"=="arm64" set arch=ARM64
|
||||
if /I "%1"=="x64" set arch=x64
|
||||
if /I "%2"=="x64" set arch=x64
|
||||
|
||||
@REM Check for Ninja Multi-Config option (-x)
|
||||
set USE_NINJA=0
|
||||
for %%a in (%*) do (
|
||||
if "%%a"=="-x" set USE_NINJA=1
|
||||
)
|
||||
|
||||
if "%USE_NINJA%"=="1" (
|
||||
echo Using Ninja Multi-Config generator
|
||||
set CMAKE_GENERATOR="Ninja Multi-Config"
|
||||
set VS_VERSION=Ninja
|
||||
goto :generator_ready
|
||||
)
|
||||
|
||||
@REM Detect Visual Studio version using msbuild
|
||||
echo Detecting Visual Studio version using msbuild...
|
||||
|
||||
@REM Try to get MSBuild version - the output format varies by VS version
|
||||
set VS_MAJOR=
|
||||
for /f "tokens=*" %%i in ('msbuild -version 2^>^&1 ^| findstr /r "^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"') do (
|
||||
for /f "tokens=1 delims=." %%a in ("%%i") do set VS_MAJOR=%%a
|
||||
set MSBUILD_OUTPUT=%%i
|
||||
goto :version_found
|
||||
)
|
||||
|
||||
@REM Alternative method for newer MSBuild versions
|
||||
if "%VS_MAJOR%"=="" (
|
||||
for /f "tokens=*" %%i in ('msbuild -version 2^>^&1 ^| findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"') do (
|
||||
for /f "tokens=1 delims=." %%a in ("%%i") do set VS_MAJOR=%%a
|
||||
set MSBUILD_OUTPUT=%%i
|
||||
goto :version_found
|
||||
)
|
||||
)
|
||||
|
||||
:version_found
|
||||
echo MSBuild version detected: %MSBUILD_OUTPUT%
|
||||
echo Major version: %VS_MAJOR%
|
||||
|
||||
if "%VS_MAJOR%"=="" (
|
||||
echo Error: Could not determine Visual Studio version from msbuild
|
||||
echo Please ensure Visual Studio and MSBuild are properly installed
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%VS_MAJOR%"=="16" (
|
||||
set VS_VERSION=2019
|
||||
set CMAKE_GENERATOR="Visual Studio 16 2019"
|
||||
) else if "%VS_MAJOR%"=="17" (
|
||||
set VS_VERSION=2022
|
||||
set CMAKE_GENERATOR="Visual Studio 17 2022"
|
||||
) else if "%VS_MAJOR%"=="18" (
|
||||
set VS_VERSION=2026
|
||||
set CMAKE_GENERATOR="Visual Studio 18 2026"
|
||||
) else (
|
||||
echo Error: Unsupported Visual Studio version: %VS_MAJOR%
|
||||
echo Supported versions: VS2019 (16.x^), VS2022 (17.x^), VS2026 (18.x^)
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Detected Visual Studio %VS_VERSION% (version %VS_MAJOR%)
|
||||
echo Using CMake generator: %CMAKE_GENERATOR%
|
||||
|
||||
:generator_ready
|
||||
|
||||
@REM Pack deps
|
||||
if "%1"=="pack" (
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
cd %WP%/deps/build
|
||||
if "%arch%"=="ARM64" cd %WP%/deps/build-arm64
|
||||
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do set build_date=%%c%%b%%a
|
||||
echo packing deps: OrcaSlicer_dep_win-!arch!_!build_date!_vs!VS_VERSION!.zip
|
||||
|
||||
%WP%/tools/7z.exe a OrcaSlicer_dep_win-!arch!_!build_date!_vs!VS_VERSION!.zip OrcaSlicer_dep
|
||||
goto :done
|
||||
)
|
||||
|
||||
set debug=OFF
|
||||
set debuginfo=OFF
|
||||
if "%1"=="debug" set debug=ON
|
||||
if "%2"=="debug" set debug=ON
|
||||
if "%1"=="debuginfo" set debuginfo=ON
|
||||
if "%2"=="debuginfo" set debuginfo=ON
|
||||
if "%debug%"=="ON" (
|
||||
set build_type=Debug
|
||||
set build_dir=build-dbg
|
||||
) else (
|
||||
if "%debuginfo%"=="ON" (
|
||||
set build_type=RelWithDebInfo
|
||||
set build_dir=build-dbginfo
|
||||
) else (
|
||||
set build_type=Release
|
||||
set build_dir=build
|
||||
)
|
||||
)
|
||||
if "%arch%"=="ARM64" set build_dir=%build_dir%-arm64
|
||||
echo build type set to %build_type%, arch=%arch%
|
||||
|
||||
setlocal DISABLEDELAYEDEXPANSION
|
||||
cd deps
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
set "SIG_FLAG="
|
||||
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
|
||||
|
||||
if "%1"=="slicer" (
|
||||
GOTO :slicer
|
||||
)
|
||||
echo "building deps.."
|
||||
|
||||
echo on
|
||||
REM Set minimum CMake policy to avoid <3.5 errors
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps
|
||||
) else (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -A %arch% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps -- -m
|
||||
)
|
||||
@echo off
|
||||
|
||||
if "%1"=="deps" goto :done
|
||||
|
||||
:slicer
|
||||
echo "building Orca Slicer..."
|
||||
cd %WP%
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
|
||||
echo on
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD
|
||||
) else (
|
||||
cmake .. -G %CMAKE_GENERATOR% -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
)
|
||||
@echo off
|
||||
cd ..
|
||||
call scripts/run_gettext.bat
|
||||
cd %build_dir%
|
||||
cmake --build . --target install --config %build_type%
|
||||
|
||||
:done
|
||||
@echo off
|
||||
for /f "tokens=1-3 delims=:.," %%a in ("%_START_TIME: =0%") do set /a "_start_s=%%a*3600+%%b*60+%%c"
|
||||
for /f "tokens=1-3 delims=:.," %%a in ("%TIME: =0%") do set /a "_end_s=%%a*3600+%%b*60+%%c"
|
||||
set /a "_elapsed=_end_s - _start_s"
|
||||
if %_elapsed% lss 0 set /a "_elapsed+=86400"
|
||||
set /a "_hours=_elapsed / 3600"
|
||||
set /a "_remainder=_elapsed - _hours * 3600"
|
||||
set /a "_mins=_remainder / 60"
|
||||
set /a "_secs=_remainder - _mins * 60"
|
||||
echo.
|
||||
echo Build completed in %_hours%h %_mins%m %_secs%s
|
||||
@@ -1,80 +0,0 @@
|
||||
@REM OrcaSlicer build script for Windows
|
||||
@echo off
|
||||
set WP=%CD%
|
||||
|
||||
@REM Pack deps
|
||||
if "%1"=="pack" (
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
cd %WP%/deps/build
|
||||
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do set build_date=%%c%%b%%a
|
||||
echo packing deps: OrcaSlicer_dep_win64_!build_date!_vs2022.zip
|
||||
|
||||
%WP%/tools/7z.exe a OrcaSlicer_dep_win64_!build_date!_vs2022.zip OrcaSlicer_dep
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
set debug=OFF
|
||||
set debuginfo=OFF
|
||||
@REM Default target architecture to the host CPU arch; override with x64/arm64 arg.
|
||||
set arch=x64
|
||||
if /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" set arch=ARM64
|
||||
if /I "%PROCESSOR_ARCHITEW6432%"=="ARM64" set arch=ARM64
|
||||
if "%1"=="debug" set debug=ON
|
||||
if "%2"=="debug" set debug=ON
|
||||
if "%1"=="debuginfo" set debuginfo=ON
|
||||
if "%2"=="debuginfo" set debuginfo=ON
|
||||
if /I "%1"=="arm64" set arch=ARM64
|
||||
if /I "%2"=="arm64" set arch=ARM64
|
||||
if /I "%1"=="x64" set arch=x64
|
||||
if /I "%2"=="x64" set arch=x64
|
||||
if "%debug%"=="ON" (
|
||||
set build_type=Debug
|
||||
set build_dir=build-dbg
|
||||
) else (
|
||||
if "%debuginfo%"=="ON" (
|
||||
set build_type=RelWithDebInfo
|
||||
set build_dir=build-dbginfo
|
||||
) else (
|
||||
set build_type=Release
|
||||
set build_dir=build
|
||||
)
|
||||
)
|
||||
if "%arch%"=="ARM64" set build_dir=%build_dir%-arm64
|
||||
echo build type set to %build_type%, arch=%arch%
|
||||
|
||||
setlocal DISABLEDELAYEDEXPANSION
|
||||
cd deps
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
set "SIG_FLAG="
|
||||
if defined ORCA_UPDATER_SIG_KEY set "SIG_FLAG=-DORCA_UPDATER_SIG_KEY=%ORCA_UPDATER_SIG_KEY%"
|
||||
|
||||
if "%1"=="slicer" (
|
||||
GOTO :slicer
|
||||
)
|
||||
echo "building deps.."
|
||||
|
||||
echo on
|
||||
REM Set minimum CMake policy to avoid <3.5 errors
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
cmake ../ -G "Visual Studio 17 2022" -A %arch% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps -- -m
|
||||
@echo off
|
||||
|
||||
if "%1"=="deps" exit /b 0
|
||||
|
||||
:slicer
|
||||
echo "building Orca Slicer..."
|
||||
cd %WP%
|
||||
mkdir %build_dir%
|
||||
cd %build_dir%
|
||||
|
||||
echo on
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
cmake .. -G "Visual Studio 17 2022" -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
@echo off
|
||||
cd ..
|
||||
call scripts/run_gettext.bat
|
||||
cd %build_dir%
|
||||
cmake --build . --target install --config %build_type%
|
||||
495
build_win.bat
Normal file
@@ -0,0 +1,495 @@
|
||||
@setlocal disableDelayedExpansion enableExtensions
|
||||
@IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off)
|
||||
@GOTO :MAIN
|
||||
:HELP
|
||||
@ECHO.
|
||||
@ECHO Performs initial build or rebuild of the app (build) and deps (build/deps).
|
||||
@ECHO Default options are determined from build directories and system state.
|
||||
@ECHO.
|
||||
@ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-VERSION ^<version^>]
|
||||
@ECHO [-PRODUCT ^<product^>] [-DESTDIR ^<directory^>]
|
||||
@ECHO [-STEPS ^<all^|all-dirty^|app^|app-dirty^|deps^|deps-dirty^>]
|
||||
@ECHO [-RUN ^<console^|custom^|none^|viewer^|window^>]
|
||||
@ECHO.
|
||||
@ECHO -a -ARCH Target processor architecture
|
||||
@ECHO Default: %PS_ARCH_HOST%
|
||||
@ECHO -c -CONFIG MSVC project config
|
||||
@ECHO Default: %PS_CONFIG_DEFAULT%
|
||||
@ECHO -v -VERSION Major version number of MSVC installation to use for build
|
||||
@ECHO Default: %PS_VERSION_SUPPORTED%
|
||||
@ECHO -p -PRODUCT Product ID of MSVC installation to use for build
|
||||
@ECHO Default: %PS_PRODUCT_DEFAULT%
|
||||
@ECHO -s -STEPS Performs only the specified build steps:
|
||||
@ECHO all - clean and build deps and app
|
||||
@ECHO all-dirty - build deps and app without cleaning
|
||||
@ECHO app - clean and build main applications
|
||||
@ECHO app-dirty - build main applications without cleaning
|
||||
@ECHO deps - clean and build deps
|
||||
@ECHO deps-dirty - build deps without cleaning
|
||||
@ECHO Default: %PS_STEPS_DEFAULT%
|
||||
@ECHO -r -RUN Specifies what to perform at the run step:
|
||||
@ECHO console - run and wait on bambu-studio-console.exe
|
||||
@ECHO custom - run and wait on your custom build/%PS_CUSTOM_RUN_FILE%
|
||||
@ECHO ide - open project in Visual Studio if not open (no wait)
|
||||
@ECHO none - run step does nothing
|
||||
@ECHO viewer - run bambu-gcodeviewer.exe (no wait)
|
||||
@ECHO window - run bambu-studio.exe (no wait)
|
||||
@ECHO Default: none
|
||||
@ECHO -d -DESTDIR Deps destination directory
|
||||
@ECHO Warning: Changing destdir path will not delete the old destdir.
|
||||
@ECHO Default: %PS_DESTDIR_DEFAULT_MSG%
|
||||
@ECHO.
|
||||
@ECHO Examples:
|
||||
@ECHO.
|
||||
@ECHO Initial build: build_win -d "c:\src\BambuSlicer-deps"
|
||||
@ECHO Build post deps change: build_win -s all
|
||||
@ECHO App dirty build: build_win
|
||||
@ECHO App dirty build ^& run: build_win -r console
|
||||
@ECHO All clean build ^& run: build_win -s all -r console -d "deps\build\out_deps"
|
||||
@ECHO.
|
||||
GOTO :END
|
||||
|
||||
:MAIN
|
||||
REM Script constants
|
||||
SET START_TIME=%TIME%
|
||||
SET PS_START_DIR=%CD%
|
||||
SET PS_SOLUTION_NAME=BambuStudio
|
||||
SET PS_CHOICE_TIMEOUT=30
|
||||
SET PS_CUSTOM_RUN_FILE=custom_run.bat
|
||||
SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt
|
||||
SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME%
|
||||
SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo"
|
||||
|
||||
REM The officially supported toolchain version is 16 (Visual Studio 2019)
|
||||
REM TODO: Update versions after Boost gets rolled to 1.78 or later
|
||||
SET PS_VERSION_SUPPORTED=16
|
||||
SET PS_VERSION_EXCEEDED=17
|
||||
SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||
IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
|
||||
FOR /F "tokens=4 USEBACKQ delims=." %%I IN (`"%VSWHERE%" -nologo -property productId`) DO SET PS_PRODUCT_DEFAULT=%%I
|
||||
IF "%PS_PRODUCT_DEFAULT%" EQU "" (
|
||||
SET EXIT_STATUS=-1
|
||||
@ECHO ERROR: No Visual Studio installation found. 1>&2
|
||||
GOTO :HELP
|
||||
)
|
||||
REM Default to the latest supported version if multiple are available
|
||||
FOR /F "tokens=1 USEBACKQ delims=." %%I IN (
|
||||
`^""%VSWHERE%" -version "[%PS_VERSION_SUPPORTED%,%PS_VERSION_EXCEEDED%)" -latest -nologo -property catalog_buildVersion^"`
|
||||
) DO SET PS_VERSION_SUPPORTED=%%I
|
||||
|
||||
REM Probe build directories and system state for reasonable default arguments
|
||||
pushd %~dp0
|
||||
SET PS_CONFIG=RelWithDebInfo
|
||||
SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64%
|
||||
CALL :TOLOWER PS_ARCH
|
||||
SET PS_RUN=none
|
||||
SET PS_DESTDIR=
|
||||
SET PS_VERSION=
|
||||
SET PS_PRODUCT=%PS_PRODUCT_DEFAULT%
|
||||
CALL :RESOLVE_DESTDIR_CACHE
|
||||
|
||||
REM Set up parameters used by help menu
|
||||
SET EXIT_STATUS=0
|
||||
SET PS_CONFIG_DEFAULT=%PS_CONFIG%
|
||||
SET PS_ARCH_HOST=%PS_ARCH%
|
||||
(echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP
|
||||
|
||||
REM Parse arguments
|
||||
SET EXIT_STATUS=1
|
||||
SET PS_CURRENT_STEP=arguments
|
||||
SET PARSER_STATE=
|
||||
SET PARSER_FAIL=
|
||||
FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN VERSION PRODUCT" PARSER_STATE "%%~I"
|
||||
IF "%PARSER_FAIL%" NEQ "" (
|
||||
@ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
|
||||
GOTO :HELP
|
||||
)ELSE IF "%PARSER_STATE%" NEQ "" (
|
||||
@ECHO ERROR: Missing parameter for: %PARSER_STATE% 1>&2
|
||||
GOTO :HELP
|
||||
)
|
||||
|
||||
REM Validate arguments
|
||||
SET PS_ASK_TO_CONTINUE=
|
||||
CALL :TOLOWER PS_ARCH
|
||||
SET PS_ARCH=%PS_ARCH:amd64=x64%
|
||||
CALL :PARSE_OPTION_VALUE %PS_CONFIG_LIST:;= % PS_CONFIG
|
||||
IF "%PS_CONFIG%" EQU "" GOTO :HELP
|
||||
REM RESOLVE_DESTDIR_CACHE must go after PS_ARCH and PS_CONFIG, but before PS STEPS
|
||||
CALL :RESOLVE_DESTDIR_CACHE
|
||||
IF "%PS_STEPS%" EQU "" SET PS_STEPS=%PS_STEPS_DEFAULT%
|
||||
CALL :PARSE_OPTION_VALUE "all all-dirty deps-dirty deps app-dirty app app-cmake" PS_STEPS
|
||||
IF "%PS_STEPS%" EQU "" GOTO :HELP
|
||||
(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 || SET PS_STEPS_DIRTY=
|
||||
IF "%PS_STEPS%" EQU "app-cmake" SET PS_STEPS_DIRTY=1
|
||||
IF "%PS_DESTDIR%" EQU "" SET PS_DESTDIR=%PS_DESTDIR_CACHED%
|
||||
IF "%PS_DESTDIR%" EQU "" (
|
||||
@ECHO ERROR: Parameter required: -DESTDIR 1>&2
|
||||
GOTO :HELP
|
||||
)
|
||||
CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%"
|
||||
IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" (
|
||||
(echo "all deps all-dirty deps-dirty")| findstr /I /C:"%PS_STEPS%">nul || (
|
||||
IF EXIST "%PS_DESTDIR%" (
|
||||
@ECHO WARNING: DESTDIR does not match cache: 1>&2
|
||||
@ECHO WARNING: new: %PS_DESTDIR% 1>&2
|
||||
@ECHO WARNING: old: %PS_DESTDIR_CACHED% 1>&2
|
||||
SET PS_ASK_TO_CONTINUE=1
|
||||
) ELSE (
|
||||
@ECHO ERROR: Invalid parameter: DESTDIR=%PS_DESTDIR% 1>&2
|
||||
GOTO :HELP
|
||||
)
|
||||
)
|
||||
)
|
||||
SET PS_DESTDIR_DEFAULT_MSG=
|
||||
CALL :PARSE_OPTION_VALUE "console custom ide none viewer window" PS_RUN
|
||||
IF "%PS_RUN%" EQU "" GOTO :HELP
|
||||
IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" (
|
||||
@ECHO ERROR: RUN=%PS_RUN% specified with STEPS=%PS_STEPS%
|
||||
@ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty"
|
||||
GOTO :HELP
|
||||
)
|
||||
IF DEFINED PS_VERSION (
|
||||
SET /A PS_VERSION_EXCEEDED=%PS_VERSION% + 1
|
||||
) ELSE SET PS_VERSION=%PS_VERSION_SUPPORTED%
|
||||
SET MSVC_FILTER=-products Microsoft.VisualStudio.Product.%PS_PRODUCT% -version "[%PS_VERSION%,%PS_VERSION_EXCEEDED%)"
|
||||
FOR /F "tokens=* USEBACKQ" %%I IN (`^""%VSWHERE%" %MSVC_FILTER% -nologo -property installationPath^"`) DO SET MSVC_DIR=%%I
|
||||
IF NOT EXIST "%MSVC_DIR%" (
|
||||
@ECHO ERROR: Compatible Visual Studio installation not found. 1>&2
|
||||
GOTO :HELP
|
||||
)
|
||||
REM Give the user a chance to cancel if we found something odd.
|
||||
IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
|
||||
@ECHO.
|
||||
@ECHO Unexpected parameters detected. Build paused for %PS_CHOICE_TIMEOUT% seconds.
|
||||
choice /T %PS_CHOICE_TIMEOUT% /C YN /D N /M "Continue"
|
||||
IF %ERRORLEVEL% NEQ 1 GOTO :HELP
|
||||
|
||||
REM Set up MSVC environment
|
||||
:BUILD_ENV
|
||||
SET EXIT_STATUS=2
|
||||
SET PS_CURRENT_STEP=environment
|
||||
@ECHO **********************************************************************
|
||||
@ECHO ** Build Config: %PS_CONFIG%
|
||||
@ECHO ** Target Arch: %PS_ARCH%
|
||||
@ECHO ** Build Steps: %PS_STEPS%
|
||||
@ECHO ** Run App: %PS_RUN%
|
||||
@ECHO ** Deps path: %PS_DESTDIR%
|
||||
@ECHO ** Using Microsoft Visual Studio installation found at:
|
||||
@ECHO ** %MSVC_DIR%
|
||||
CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO :END
|
||||
REM Need to reset the echo state after vsdevcmd.bat clobbers it.
|
||||
@IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off)
|
||||
IF "%PS_DRY_RUN_ONLY%" NEQ "" (
|
||||
@ECHO Script terminated early because PS_DRY_RUN_ONLY is set. 1>&2
|
||||
GOTO :END
|
||||
)
|
||||
IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP
|
||||
|
||||
REM Build deps
|
||||
:BUILD_DEPS
|
||||
SET EXIT_STATUS=3
|
||||
SET PS_CURRENT_STEP=deps
|
||||
IF "%PS_STEPS_DIRTY%" EQU "" (
|
||||
CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" .vs
|
||||
CALL :MAKE_OR_CLEAN_DIRECTORY "%PS_DESTDIR%"
|
||||
)
|
||||
cd deps\build || GOTO :END
|
||||
cmake.exe .. -DDESTDIR="%PS_DESTDIR%"
|
||||
IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
|
||||
(del CMakeCache.txt && cmake.exe .. -DDESTDIR="%PS_DESTDIR%") || GOTO :END
|
||||
) ELSE GOTO :END
|
||||
(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%"
|
||||
msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
|
||||
cd ..\..
|
||||
IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP
|
||||
|
||||
REM Build app
|
||||
:BUILD_APP
|
||||
SET EXIT_STATUS=4
|
||||
SET PS_CURRENT_STEP=app
|
||||
IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" .vs
|
||||
cd build || GOTO :END
|
||||
REM Make sure we have a custom batch file skeleton for the run stage
|
||||
set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE%
|
||||
CALL :CANONICALIZE_PATH PS_CUSTOM_BAT
|
||||
IF NOT EXIST %PS_CUSTOM_BAT% CALL :WRITE_CUSTOM_SCRIPT_SKELETON %PS_CUSTOM_BAT%
|
||||
SET PS_PROJECT_IS_OPEN=
|
||||
FOR /F "tokens=2 delims=," %%I in (
|
||||
'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"'
|
||||
) do SET PS_PROJECT_IS_OPEN=%%~I
|
||||
cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%
|
||||
IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
|
||||
(del CMakeCache.txt && cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%) || GOTO :END
|
||||
) ELSE GOTO :END
|
||||
REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv
|
||||
IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
|
||||
(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
|
||||
|
||||
REM Run app
|
||||
:RUN_APP
|
||||
REM All build steps complete.
|
||||
CALL :DIFF_TIME ELAPSED_TIME %START_TIME% %TIME%
|
||||
IF "%PS_CURRENT_STEP%" NEQ "arguments" (
|
||||
@ECHO.
|
||||
@ECHO Total Build Time Elapsed %ELAPSED_TIME%
|
||||
)
|
||||
SET EXIT_STATUS=5
|
||||
SET PS_CURRENT_STEP=run
|
||||
IF "%PS_RUN%" EQU "none" GOTO :PROLOGUE
|
||||
cd src\%PS_CONFIG% || GOTO :END
|
||||
SET PS_PROJECT_IS_OPEN=
|
||||
FOR /F "tokens=2 delims=," %%I in (
|
||||
'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"'
|
||||
) do SET PS_PROJECT_IS_OPEN=%%~I
|
||||
@ECHO.
|
||||
@ECHO Running %PS_RUN% application...
|
||||
@REM icacls below is just a hack for file-not-found error handling
|
||||
IF "%PS_RUN%" EQU "console" (
|
||||
icacls bambu-studio-console.exe >nul || GOTO :END
|
||||
start /wait /b bambu-studio-console.exe
|
||||
) ELSE IF "%PS_RUN%" EQU "window" (
|
||||
icacls bambu-studio.exe >nul || GOTO :END
|
||||
start bambu-studio.exe
|
||||
) ELSE IF "%PS_RUN%" EQU "viewer" (
|
||||
icacls bambu-gcodeviewer.exe >nul || GOTO :END
|
||||
start bambu-gcodeviewer.exe
|
||||
) ELSE IF "%PS_RUN%" EQU "custom" (
|
||||
icacls %PS_CUSTOM_BAT% >nul || GOTO :END
|
||||
CALL %PS_CUSTOM_BAT%
|
||||
) ELSE IF "%PS_RUN%" EQU "ide" (
|
||||
IF "%PS_PROJECT_IS_OPEN%" NEQ "" (
|
||||
@ECHO WARNING: Solution is already open in Visual Studio. Skipping ide run step. 1>&2
|
||||
) ELSE (
|
||||
@ECHO Preparing to run Visual Studio...
|
||||
cd ..\.. || GOTO :END
|
||||
REM This hack generates a single config for MSVS, guaranteeing it gets set as the active config.
|
||||
cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG% > nul 2> nul || GOTO :END
|
||||
REM Now launch devenv with the single config (setting it active) and a /command switch to re-run cmake and generate the full config list
|
||||
start devenv.exe %PS_SOLUTION_NAME%.sln /command ^"shell /o ^^^"%~f0^^^" -d ^^^"%PS_DESTDIR%^^^" -c %PS_CONFIG% -a %PS_ARCH% -r none -s app-cmake^"
|
||||
REM If devenv fails to launch just directly regenerate the full config list.
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% 2> nul 1> nul || GOTO :END
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@REM ********** DON'T ADD ANY CODE BETWEEN THESE TWO SECTIONS **********
|
||||
@REM RUN_APP may hand off control, so let exit codes fall through to PROLOGUE.
|
||||
|
||||
:PROLOGUE
|
||||
SET EXIT_STATUS=%ERRORLEVEL%
|
||||
:END
|
||||
@IF "%PS_ECHO_ON%%PS_DRY_RUN_ONLY%" NEQ "" (
|
||||
@ECHO **********************************************************************
|
||||
@ECHO ** Script Parameters:
|
||||
@ECHO **********************************************************************
|
||||
@SET PS_
|
||||
)
|
||||
IF "%EXIT_STATUS%" NEQ "0" (
|
||||
IF "%PS_CURRENT_STEP%" NEQ "arguments" (
|
||||
@ECHO.
|
||||
@ECHO ERROR: *** Build process failed at %PS_CURRENT_STEP% step. *** 1>&2
|
||||
)
|
||||
) ELSE (
|
||||
@ECHO All steps completed successfully.
|
||||
)
|
||||
popd
|
||||
exit /B %EXIT_STATUS%
|
||||
|
||||
GOTO :EOF
|
||||
REM Functions and stubs start here.
|
||||
|
||||
:RESOLVE_DESTDIR_CACHE
|
||||
@REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT
|
||||
@REM Note: This just sets global variables, so it doesn't use setlocal.
|
||||
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
|
||||
mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
|
||||
REM Copy a legacy file if we don't have one in the proper location.
|
||||
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%" > nul 2> nul
|
||||
CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
|
||||
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
|
||||
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (
|
||||
SET PS_DESTDIR_CACHED=%%I
|
||||
SET PS_DESTDIR_DEFAULT_MSG=%%I
|
||||
)
|
||||
SET PS_STEPS_DEFAULT=app-dirty
|
||||
) ELSE IF EXIST "%PS_DEPS_PATH_FILE%" (
|
||||
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO (
|
||||
SET PS_DESTDIR_CACHED=%%I
|
||||
SET PS_DESTDIR_DEFAULT_MSG=%%I
|
||||
)
|
||||
SET PS_STEPS_DEFAULT=app
|
||||
) ELSE (
|
||||
SET PS_DESTDIR_CACHED=
|
||||
SET PS_DESTDIR_DEFAULT_MSG=Cache missing. Argument required.
|
||||
SET PS_STEPS_DEFAULT=all
|
||||
)
|
||||
GOTO :EOF
|
||||
|
||||
:PARSE_OPTION
|
||||
@REM Argument parser called for each argument
|
||||
@REM %1 - Valid option list
|
||||
@REM %2 - Variable name for parser state; must be unset when parsing finished
|
||||
@REM %3 - Current argument value
|
||||
@REM PARSER_FAIL will be set on an error
|
||||
@REM Note: Must avoid delayed expansion since filenames may contain ! character
|
||||
setlocal disableDelayedExpansion
|
||||
IF "%PARSER_FAIL%" NEQ "" GOTO :EOF
|
||||
CALL SET LAST_ARG=%%%2%%
|
||||
IF "%LAST_ARG%" EQU "" (
|
||||
CALL :PARSE_OPTION_NAME %1 %~2 %~3 1
|
||||
SET ARG_TYPE=NAME
|
||||
) ELSE (
|
||||
SET PS_SET_COMMAND=SET PS_%LAST_ARG%=%~3
|
||||
SET ARG_TYPE=LAST_ARG
|
||||
SET %~2=
|
||||
)
|
||||
CALL SET LAST_ARG=%%%2%%
|
||||
IF "%LAST_ARG%%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=%~3
|
||||
(
|
||||
endlocal
|
||||
SET PARSER_FAIL=%PARSER_FAIL%
|
||||
SET %~2=%LAST_ARG%
|
||||
%PS_SET_COMMAND%
|
||||
)
|
||||
GOTO :EOF
|
||||
|
||||
:PARSE_OPTION_VALUE
|
||||
setlocal disableDelayedExpansion
|
||||
@REM Parses value and verifies it is within the supplied list
|
||||
@REM %1 - Valid option list
|
||||
@REM %2 - In/out variable name; unset on error
|
||||
CALL SET NAME=%~2
|
||||
CALL SET SAVED_VALUE=%%%NAME%%%
|
||||
CALL :PARSE_OPTION_NAME %1 %NAME% -%SAVED_VALUE%
|
||||
CALL SET NEW_VALUE=%%%NAME%%%
|
||||
IF "%NEW_VALUE%" EQU "" (
|
||||
@ECHO ERROR: Invalid parameter: %NAME:~3%=%SAVED_VALUE% 1>&2
|
||||
)
|
||||
endlocal & SET %NAME%=%NEW_VALUE%
|
||||
GOTO :EOF
|
||||
|
||||
:PARSE_OPTION_NAME
|
||||
@REM Parses an option name
|
||||
@REM %1 - Valid option list
|
||||
@REM %2 - Out variable name; unset on error
|
||||
@REM %3 - Current argument value
|
||||
@REM %4 - Boolean indicating single character switches are valid
|
||||
@REM Note: Delayed expansion safe because ! character is invalid in option name
|
||||
setlocal enableDelayedExpansion
|
||||
IF "%4" NEQ "" FOR %%I IN (%~1) DO @(
|
||||
SET SHORT_NAME=%%~I
|
||||
SET SHORT_ARG_!SHORT_NAME:~0,1!=%%~I
|
||||
)
|
||||
@SET OPTION_NAME=%~3
|
||||
@(echo %OPTION_NAME%)| findstr /R /C:"[-/]..*">nul || GOTO :PARSE_OPTION_NAME_FAIL
|
||||
@SET OPTION_NAME=%OPTION_NAME:~1%
|
||||
IF "%4" NEQ "" (
|
||||
IF "%OPTION_NAME%" EQU "%OPTION_NAME:~0,1%" (
|
||||
IF "!SHORT_ARG_%OPTION_NAME:~0,1%!" NEQ "" SET OPTION_NAME=!SHORT_ARG_%OPTION_NAME:~0,1%!
|
||||
)
|
||||
)
|
||||
@(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL
|
||||
@(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL
|
||||
FOR %%I IN (%~1) DO SET OPTION_NAME=!OPTION_NAME:%%~I=%%~I!
|
||||
endlocal & SET %~2=%OPTION_NAME%
|
||||
GOTO :EOF
|
||||
:PARSE_OPTION_NAME_FAIL
|
||||
endlocal & SET %~2=
|
||||
GOTO :EOF
|
||||
|
||||
:MAKE_OR_CLEAN_DIRECTORY
|
||||
@REM Create directory if it doesn't exist or clean it if it does
|
||||
@REM %1 - Directory path to clean or create
|
||||
@REM %* - Optional list of files/dirs to keep (in the base directory only)
|
||||
setlocal disableDelayedExpansion
|
||||
IF NOT EXIST "%~1" (
|
||||
@ECHO Creating %~1
|
||||
mkdir "%~1" && (
|
||||
endlocal
|
||||
GOTO :EOF
|
||||
)
|
||||
)
|
||||
@ECHO Cleaning %~1 ...
|
||||
SET KEEP_LIST=
|
||||
:MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP
|
||||
IF "%~2" NEQ "" (
|
||||
SET KEEP_LIST=%KEEP_LIST% "%~2"
|
||||
SHIFT /2
|
||||
GOTO :MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP
|
||||
)
|
||||
for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do (
|
||||
(echo %KEEP_LIST%)| findstr /I /L /C:"\"%%I\"">nul || (
|
||||
rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I"
|
||||
)
|
||||
endlocal
|
||||
GOTO :EOF
|
||||
|
||||
:TOLOWER
|
||||
@REM Converts supplied environment variable to lowercase
|
||||
@REM %1 - Input/output variable name
|
||||
@REM Note: This is slow on very long strings, but is used only on very short ones
|
||||
setlocal disableDelayedExpansion
|
||||
@FOR %%b IN (a b c d e f g h i j k l m n o p q r s t u v w x y z) DO @CALL set %~1=%%%1:%%b=%%b%%
|
||||
@CALL SET OUTPUT=%%%~1%%
|
||||
endlocal & SET %~1=%OUTPUT%
|
||||
GOTO :EOF
|
||||
|
||||
:CANONICALIZE_PATH
|
||||
@REM Canonicalizes the path in the supplied variable
|
||||
@REM %1 - Input/output variable containing path to canonicalize
|
||||
@REM %2 - Optional base directory
|
||||
setlocal
|
||||
CALL :CANONICALIZE_PATH_INNER %1 %%%~1%% %2
|
||||
endlocal & SET %~1=%OUTPUT%
|
||||
GOTO :EOF
|
||||
:CANONICALIZE_PATH_INNER
|
||||
if "%~3" NEQ "" (pushd %3 || GOTO :EOF)
|
||||
SET OUTPUT=%~f2
|
||||
if "%~3" NEQ "" popd
|
||||
GOTO :EOF
|
||||
|
||||
:DIFF_TIME
|
||||
@REM Calculates elapsed time between two timestamps (TIME environment variable format)
|
||||
@REM %1 - Output variable
|
||||
@REM %2 - Start time
|
||||
@REM %3 - End time
|
||||
setlocal EnableDelayedExpansion
|
||||
set START_ARG=%2
|
||||
set END_ARG=%3
|
||||
set END=!END_ARG:%TIME:~8,1%=%%100)*100+1!
|
||||
set START=!START_ARG:%TIME:~8,1%=%%100)*100+1!
|
||||
set /A DIFF=((((10!END:%TIME:~2,1%=%%100)*60+1!%%100)-((((10!START:%TIME:~2,1%=%%100)*60+1!%%100), DIFF-=(DIFF^>^>31)*24*60*60*100
|
||||
set /A CC=DIFF%%100+100,DIFF/=100,SS=DIFF%%60+100,DIFF/=60,MM=DIFF%%60+100,HH=DIFF/60+100
|
||||
@endlocal & set %1=%HH:~1%%TIME:~2,1%%MM:~1%%TIME:~2,1%%SS:~1%%TIME:~8,1%%CC:~1%
|
||||
@GOTO :EOF
|
||||
|
||||
:WRITE_CUSTOM_SCRIPT_SKELETON
|
||||
@REM Writes the following text to the supplied file
|
||||
@REM %1 - Output filename
|
||||
setlocal
|
||||
@(
|
||||
ECHO @ECHO.
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO ** This is a custom run script skeleton.
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO.
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO ** The working directory is:
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO dir
|
||||
ECHO @ECHO.
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO ** The environment is:
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO set
|
||||
ECHO @ECHO.
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO ** Edit or replace this script to run custom steps after a successful build:
|
||||
ECHO @ECHO ** %~1
|
||||
ECHO @ECHO ********************************************************************************
|
||||
ECHO @ECHO.
|
||||
) > "%~1"
|
||||
endlocal
|
||||
GOTO :EOF
|
||||
175
cmake/modules/Catch2/Catch.cmake
Normal file
@@ -0,0 +1,175 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_PREFIX='${_TEST_PREFIX}'"
|
||||
-D "TEST_SUFFIX='${_TEST_SUFFIX}'"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if (NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
)
|
||||
106
cmake/modules/Catch2/CatchAddTests.cmake
Normal file
@@ -0,0 +1,106 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
macro(_add_catch_test_labels LINE)
|
||||
# convert to list of tags
|
||||
string(REPLACE "][" "]\\;[" tags ${line})
|
||||
|
||||
add_command(
|
||||
set_tests_properties "${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
LABELS "${tags}"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
macro(_add_catch_test LINE)
|
||||
set(test ${line})
|
||||
# use escape commas to handle properly test cases with commans inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(
|
||||
add_test "${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"${test_name}"
|
||||
${extra_args}
|
||||
)
|
||||
|
||||
add_command(
|
||||
set_tests_properties "${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endmacro()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-tests
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||
)
|
||||
elseif(${result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
set(test)
|
||||
set(tags_regex "(\\[([^\\[]*)\\])+$")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
# lines without leading whitespaces are catch output not tests
|
||||
if(${line} MATCHES "^[ \t]+")
|
||||
# strip leading spaces and tabs
|
||||
string(REGEX REPLACE "^[ \t]+" "" line ${line})
|
||||
|
||||
if(${line} MATCHES "${tags_regex}")
|
||||
_add_catch_test_labels(${line})
|
||||
else()
|
||||
_add_catch_test(${line})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
225
cmake/modules/Catch2/ParseAndAddCatchTests.cmake
Normal file
@@ -0,0 +1,225 @@
|
||||
#==================================================================================================#
|
||||
# supported macros #
|
||||
# - TEST_CASE, #
|
||||
# - SCENARIO, #
|
||||
# - TEST_CASE_METHOD, #
|
||||
# - CATCH_TEST_CASE, #
|
||||
# - CATCH_SCENARIO, #
|
||||
# - CATCH_TEST_CASE_METHOD. #
|
||||
# #
|
||||
# Usage #
|
||||
# 1. make sure this module is in the path or add this otherwise: #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# 2. make sure that you've enabled testing option for the project by the call: #
|
||||
# enable_testing() #
|
||||
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
||||
# project(testing_target) #
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||
# enable_testing() #
|
||||
# #
|
||||
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
|
||||
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
|
||||
# #
|
||||
# file(GLOB SOURCE_FILES "*.cpp") #
|
||||
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
||||
# #
|
||||
# include(ParseAndAddCatchTests) #
|
||||
# ParseAndAddCatchTests(${PROJECT_NAME}) #
|
||||
# #
|
||||
# The following variables affect the behavior of the script: #
|
||||
# #
|
||||
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
|
||||
# -- enables debug messages #
|
||||
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
|
||||
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
|
||||
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
|
||||
# -- adds fixture class name to the test name #
|
||||
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
||||
# -- adds cmake target name to the test name #
|
||||
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
||||
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
||||
# #
|
||||
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
|
||||
# a test should be run. For instance to use test MPI, one can write #
|
||||
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
|
||||
# just before calling this ParseAndAddCatchTests function #
|
||||
# #
|
||||
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
|
||||
# command. For example, to include successful tests in the output, one can write #
|
||||
# set(AdditionalCatchParameters --success) #
|
||||
# #
|
||||
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
|
||||
# file in the target is set, and contains the list of the tests extracted from that target, or #
|
||||
# from that file. This is useful, for example to add further labels or properties to the tests. #
|
||||
# #
|
||||
#==================================================================================================#
|
||||
|
||||
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
|
||||
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
|
||||
endif()
|
||||
|
||||
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
||||
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
||||
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
|
||||
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
||||
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
||||
|
||||
function(ParseAndAddCatchTests_PrintDebugMessage)
|
||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# This removes the contents between
|
||||
# - block comments (i.e. /* ... */)
|
||||
# - full line comments (i.e. // ... )
|
||||
# contents have been read into '${CppCode}'.
|
||||
# !keep partial line comments
|
||||
function(ParseAndAddCatchTests_RemoveComments CppCode)
|
||||
string(ASCII 2 CMakeBeginBlockComment)
|
||||
string(ASCII 3 CMakeEndBlockComment)
|
||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
||||
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
||||
|
||||
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Worker function
|
||||
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
||||
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
|
||||
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
|
||||
return()
|
||||
endif()
|
||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||
if(NOT EXISTS ${SourceFile})
|
||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||
return()
|
||||
endif()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
|
||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||
|
||||
# Remove block and fullline comments
|
||||
ParseAndAddCatchTests_RemoveComments(Contents)
|
||||
|
||||
# Find definition of test names
|
||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||
|
||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(TestName ${Tests})
|
||||
# Strip newlines
|
||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||
|
||||
# Get test type and fixture if applicable
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
||||
|
||||
# Get string parts of test definition
|
||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||
|
||||
# Strip wrapping quotation marks
|
||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||
|
||||
# Validate that a test name and tags have been provided
|
||||
list(LENGTH TestStrings TestStringsLength)
|
||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||
endif()
|
||||
|
||||
# Assign name and tags
|
||||
list(GET TestStrings 0 Name)
|
||||
if("${TestType}" STREQUAL "SCENARIO")
|
||||
set(Name "Scenario: ${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
||||
set(CTestName "${TestFixture}:${Name}")
|
||||
else()
|
||||
set(CTestName "${Name}")
|
||||
endif()
|
||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||
set(CTestName "${TestTarget}:${CTestName}")
|
||||
endif()
|
||||
# add target to labels to enable running all tests added from this target
|
||||
set(Labels ${TestTarget})
|
||||
if(TestStringsLength EQUAL 2)
|
||||
list(GET TestStrings 1 Tags)
|
||||
string(TOLOWER "${Tags}" Tags)
|
||||
# remove target from labels if the test is hidden
|
||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||
list(REMOVE_ITEM Labels ${TestTarget})
|
||||
endif()
|
||||
string(REPLACE "]" ";" Tags "${Tags}")
|
||||
string(REPLACE "[" "" Tags "${Tags}")
|
||||
else()
|
||||
# unset tags variable from previous loop
|
||||
unset(Tags)
|
||||
endif()
|
||||
|
||||
list(APPEND Labels ${Tags})
|
||||
|
||||
set(HiddenTagFound OFF)
|
||||
foreach(label ${Labels})
|
||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||
if(result)
|
||||
set(HiddenTagFound ON)
|
||||
break()
|
||||
endif(result)
|
||||
endforeach(label)
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||
else()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||
if(Labels)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
|
||||
endif()
|
||||
|
||||
# Escape commas in the test spec
|
||||
string(REPLACE "," "\\," Name ${Name})
|
||||
|
||||
# Add the test and set its properties
|
||||
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
|
||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
|
||||
else()
|
||||
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||
LABELS "${Labels}")
|
||||
endif()
|
||||
set_property(
|
||||
TARGET ${TestTarget}
|
||||
APPEND
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
||||
set_property(
|
||||
SOURCE ${SourceFile}
|
||||
APPEND
|
||||
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
|
||||
endif()
|
||||
|
||||
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# entry point
|
||||
function(ParseAndAddCatchTests TestTarget)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||
foreach(SourceFile ${SourceFiles})
|
||||
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
|
||||
endforeach()
|
||||
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||
endfunction()
|
||||
@@ -1,26 +0,0 @@
|
||||
set(_q "")
|
||||
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
|
||||
set(_q QUIET)
|
||||
set(_quietly TRUE)
|
||||
endif()
|
||||
find_package(${CMAKE_FIND_PACKAGE_NAME} ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} CONFIG ${_q})
|
||||
|
||||
if (NOT ${CMAKE_FIND_PACKAGE_NAME}_FOUND)
|
||||
include(CheckIncludeFileCXX)
|
||||
add_library(draco INTERFACE)
|
||||
target_include_directories(draco INTERFACE include)
|
||||
|
||||
if (_quietly)
|
||||
set(CMAKE_REQUIRED_QUIET ON)
|
||||
endif()
|
||||
CHECK_INCLUDE_FILE_CXX("draco/draco_features.h" HAVE_DRACO_H)
|
||||
|
||||
if (NOT HAVE_DRACO_H)
|
||||
if (${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Draco library not found. Please install the dependency.")
|
||||
elseif(NOT _quietly)
|
||||
message(WARNING "Draco library not found.")
|
||||
endif()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||