Compare commits
8 Commits
developmen
...
3.0.x-stab
Author | SHA1 | Date | |
---|---|---|---|
|
901e53da76 | ||
|
99118e06e6 | ||
|
624552c168 | ||
|
d49e791346 | ||
|
c1747c81b4 | ||
|
20ce3e4c47 | ||
|
75bcaea423 | ||
|
33fc1ba08a |
@ -1,37 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
---
|
|
||||||
BasedOnStyle: WebKit
|
|
||||||
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignEscapedNewlines: DontAlign
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: "false"
|
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
|
||||||
AllowShortIfStatementsOnASingleLine: "false"
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortLoopsOnASingleLine: "false"
|
|
||||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
|
||||||
BinPackArguments: "false"
|
|
||||||
BinPackParameters: "false"
|
|
||||||
BreakBeforeBraces: Allman
|
|
||||||
BreakBeforeTernaryOperators: "true"
|
|
||||||
BreakConstructorInitializers: BeforeComma
|
|
||||||
ColumnLimit: 120
|
|
||||||
Cpp11BracedListStyle: "false"
|
|
||||||
FixNamespaceComments: "true"
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IndentWidth: "4"
|
|
||||||
InsertBraces: "true"
|
|
||||||
MaxEmptyLinesToKeep: "2"
|
|
||||||
NamespaceIndentation: None
|
|
||||||
PointerAlignment: Left
|
|
||||||
ReflowComments: "false"
|
|
||||||
SortIncludes: "true"
|
|
||||||
SpaceAfterCStyleCast: "false"
|
|
||||||
SpaceInEmptyBlock: "false"
|
|
||||||
SpacesBeforeTrailingComments: "2"
|
|
||||||
SpacesInAngles: "true"
|
|
||||||
SpacesInParentheses: "true"
|
|
||||||
SpacesInSquareBrackets: "true"
|
|
||||||
Standard: c++17
|
|
@ -1,5 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
# http://EditorConfig.org
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
@ -8,22 +7,7 @@ charset = utf-8
|
|||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[CMakeLists.txt]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.cmake]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.{py,cpp,h}]
|
[*.{py,cpp,h}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
[*.sh]
|
|
||||||
indent_style = tab
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
|
10
.gersemirc
10
.gersemirc
@ -1,10 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
#
|
|
||||||
# Gersemi configuration
|
|
||||||
color: false
|
|
||||||
definitions: [ CMakeModules/CalamaresAddTest.cmake ]
|
|
||||||
line_length: 120
|
|
||||||
quiet: false
|
|
||||||
unsafe: false
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
#
|
|
||||||
18fef8dfe5d926ec0bc979562553adf4db8db2e9
|
|
||||||
874a0c1f38b0da4e5bc83083b13a63b1c7eed935
|
|
18
.gitattributes
vendored
18
.gitattributes
vendored
@ -1,14 +1,6 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
.tx/* export-ignore
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
hacking/* export-ignore
|
||||||
|
HACKING.md export-ignore
|
||||||
.editorconfig export-ignore
|
.editorconfig export-ignore
|
||||||
.gitattributes export-ignore
|
src/modules/testmodule.py export-ignore
|
||||||
.github export-ignore
|
|
||||||
.gitignore export-ignore
|
|
||||||
.gitmodules export-ignore
|
|
||||||
.travis.yml export-ignore
|
|
||||||
.tx export-ignore
|
|
||||||
|
|
||||||
src/modules/testmodule.py export-ignore
|
|
||||||
src/modules/globalStorage.yaml export-ignore
|
src/modules/globalStorage.yaml export-ignore
|
||||||
|
|
||||||
|
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,26 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
> Hi! Thank you for helping improve Calamares. If you are seeing a problem in installing a specific distribution, you should **probably** report the problem in the distribution's bug tracker, first. That helps filter out issues with packaging, mis-configuration, etc. that Calamares has no control over. If you are a distribution packager or maintainer, this page is for you.
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is. Please include 32/64 bit machine details, EFI/BIOS details, and disk setup.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots and Logs**
|
|
||||||
If applicable, add screenshots to help explain your problem. Calamares has an installation log (usually `~/.cache/calamares/session.log`), please check it for confidential information and attach it if possible.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
63
.github/ISSUE_TEMPLATE/usability_test.md
vendored
63
.github/ISSUE_TEMPLATE/usability_test.md
vendored
@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
name: Usability testing
|
|
||||||
about: Propose a usability test to help us
|
|
||||||
---
|
|
||||||
# Objective
|
|
||||||
The test goals. e.g.: Evaluate the language selection and the partitioning configurations.
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
|
|
||||||
## Environment
|
|
||||||
What is the environment that should be tested and how it should be prepared. e.g.: The test needs to run in the release 3.32.34 installing Manjaro.
|
|
||||||
|
|
||||||
## User profile
|
|
||||||
Describe the target users you are looking for the test. e.g.: A user that has already used a system-installer.
|
|
||||||
|
|
||||||
## Facilitator
|
|
||||||
What the facilitator should be familiar with to run the tests. e.g.: The facilitator needs to know how to build Calamares to be able to run the tests.
|
|
||||||
|
|
||||||
# Test design
|
|
||||||
## Tasks
|
|
||||||
A list of tasks that the user has to perform. e.g.:
|
|
||||||
|
|
||||||
* Use another language.
|
|
||||||
* Change partitioning configurations.
|
|
||||||
|
|
||||||
## Scenarios
|
|
||||||
A list of scenarios for the user to perform the tasks. They should put the user in a context and not give specific hints about what you want the user to do. e.g.:
|
|
||||||
|
|
||||||
1. You want to change the installer language to English. Please, look for this option in the application.
|
|
||||||
2. You are a big fan of a lot of distributions and want to have some space left to install other distributions in your disk after this installation. Please, resize your disk to have 35GB of space left.
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
## Results
|
|
||||||
|
|
||||||
Uncomment this session once you have your results.
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
| - | User 1 | User 2 | User 3 | User 4 | User 5 |
|
|
||||||
|:------:|:------:|:--------:|:------------------:|:------:|:------:|
|
|
||||||
| Task 1 | :x: | :question: | :heavy_check_mark: | :x: | :heavy_check_mark: |
|
|
||||||
| Task 2 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
||||||
| Task 3 | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
|
|
||||||
| Task 4 | :heavy_check_mark: | :question: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
||||||
|
|
||||||
### Task 1
|
|
||||||
|
|
||||||
#### What went well?
|
|
||||||
Describe what happened as expected. e.g.: Most users intuitively found the language selector for changing the installer language.
|
|
||||||
|
|
||||||
#### What were the challenges?
|
|
||||||
Describe where the users had issues and why. Try to write the details to ensure a good understanding of what happened. You can also attach videos, GIFs, or screenshots to illustrate. e.g.: Two of the users had issues searching for English on the language selector because they didn't realize they could scroll down to find it.
|
|
||||||
|
|
||||||
### Task 2
|
|
||||||
|
|
||||||
#### What went well?
|
|
||||||
Describe what happened as expected. e.g.: Most users intuitively found the language selector for changing the installer language.
|
|
||||||
|
|
||||||
#### What were the challenges?
|
|
||||||
Describe where the users had issues and why. Try to write the details to ensure a good understanding of what happened. You can also attach videos, GIFs, or screenshots to illustrate. e.g.: Two of the users had issues searching for English on the language selector because they didn't realize they could scroll down to find it.
|
|
||||||
|
|
||||||
-->
|
|
18
.github/workflows/issues.yml
vendored
18
.github/workflows/issues.yml
vendored
@ -1,18 +0,0 @@
|
|||||||
name: issues
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened, reopened, closed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
notify:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "remove in-progress label"
|
|
||||||
if: github.event.issue.state != 'open'
|
|
||||||
run: |
|
|
||||||
curl -X DELETE \
|
|
||||||
-H 'Accept: application/vnd.github.v3+json' \
|
|
||||||
-H 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
|
|
||||||
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/labels/hacking%3A%20in-progress"
|
|
||||||
|
|
36
.github/workflows/nightly-debian.yml
vendored
36
.github/workflows/nightly-debian.yml
vendored
@ -1,36 +0,0 @@
|
|||||||
name: nightly-debian-11
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "12 23 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://debian:11
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get -y install git-core jq curl
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-debian11.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
36
.github/workflows/nightly-fedora-qt6-boost.yml
vendored
36
.github/workflows/nightly-fedora-qt6-boost.yml
vendored
@ -1,36 +0,0 @@
|
|||||||
name: nightly-fedora-qt6-boost
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "52 2 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DWITH_QT6=ON
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
-DWITH_PYBIND11=OFF
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://registry.fedoraproject.org/fedora:40
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: yum install -y git-core jq curl
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-fedora-qt6-boost.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
35
.github/workflows/nightly-fedora-qt6.yml
vendored
35
.github/workflows/nightly-fedora-qt6.yml
vendored
@ -1,35 +0,0 @@
|
|||||||
name: nightly-fedora-qt6
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "52 2 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DWITH_QT6=ON
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://registry.fedoraproject.org/fedora:40
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: yum install -y git-core jq curl
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-fedora-qt6.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
37
.github/workflows/nightly-opensuse.yml
vendored
37
.github/workflows/nightly-opensuse.yml
vendored
@ -1,37 +0,0 @@
|
|||||||
name: nightly-opensuse
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "32 23 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DBUILD_SCHEMA_TESTING=ON
|
|
||||||
-DBUILD_TESTING=ON
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
-DWITH_QT6=ON
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://opensuse/tumbleweed
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: zypper --non-interactive in git-core jq curl
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-opensuse-qt6.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
36
.github/workflows/nightly-ubuntu.yml
vendored
36
.github/workflows/nightly-ubuntu.yml
vendored
@ -1,36 +0,0 @@
|
|||||||
name: nightly-ubuntu
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "12 23 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://ubuntu:devel
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get -y install git-core jq curl ninja-build
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-ubuntu.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
43
.github/workflows/push.yml
vendored
43
.github/workflows/push.yml
vendored
@ -1,43 +0,0 @@
|
|||||||
name: ci-push
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- calamares
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- reopened
|
|
||||||
- synchronize
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DWITH_QT6=ON
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
|
|
||||||
GIT_HASH: ${{ github.event.head_commit.id }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://registry.fedoraproject.org/fedora:40
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: yum install -y git-core jq curl
|
|
||||||
- name: "prepare source"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-fedora-qt6.sh
|
|
||||||
- name: "build"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
47
.github/workflows/weekly-debian.yml
vendored
47
.github/workflows/weekly-debian.yml
vendored
@ -1,47 +0,0 @@
|
|||||||
name: weekly-debian-11
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "12 11 * * 3"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDDIR: /build
|
|
||||||
SRCDIR: ${{ github.workspace }}
|
|
||||||
CMAKE_ARGS: |
|
|
||||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug
|
|
||||||
-DBUILD_APPSTREAM=ON
|
|
||||||
-DBUILD_APPDATA=ON
|
|
||||||
-DBUILD_TESTING=ON
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: docker://debian:11
|
|
||||||
options: --tmpfs /build:rw --user 0:0
|
|
||||||
steps:
|
|
||||||
- name: "prepare git"
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get -y install git-core jq curl
|
|
||||||
apt-get -y install pylint python3-pylint-common
|
|
||||||
- name: "prepare source (core)"
|
|
||||||
uses: calamares/actions/generic-checkout@v5
|
|
||||||
- name: "prepare source (extensions)"
|
|
||||||
shell: bash
|
|
||||||
run: git clone https://github.com/calamares/calamares-extensions.git ${SRCDIR}/calamares-extensions
|
|
||||||
- name: "install dependencies"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/deps-debian11.sh
|
|
||||||
- name: "build (core)"
|
|
||||||
shell: bash
|
|
||||||
run: ./ci/build.sh
|
|
||||||
- name: "build (extensions)"
|
|
||||||
shell: bash
|
|
||||||
run: BUILDDIR=/build/calamares-extensions SRCDIR=${SRCDIR}/calamares-extensions ./ci/build.sh
|
|
||||||
- name: "test (core)"
|
|
||||||
shell: bash
|
|
||||||
run: ctest --test-dir /build -V
|
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,6 +1,3 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
#
|
|
||||||
# C++ objects and libs
|
# C++ objects and libs
|
||||||
|
|
||||||
*.slo
|
*.slo
|
||||||
@ -24,7 +21,6 @@ __pycache__
|
|||||||
*.pro.user
|
*.pro.user
|
||||||
*.pro.user.*
|
*.pro.user.*
|
||||||
*.moc
|
*.moc
|
||||||
*.qmlc
|
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
ui_*.h
|
ui_*.h
|
||||||
@ -50,8 +46,3 @@ CMakeLists.txt.user
|
|||||||
|
|
||||||
# Backup files
|
# Backup files
|
||||||
*~
|
*~
|
||||||
*.bak
|
|
||||||
|
|
||||||
# Kate
|
|
||||||
*.kate-swp
|
|
||||||
tags
|
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "thirdparty/libcrashreporter-qt"]
|
||||||
|
path = thirdparty/libcrashreporter-qt
|
||||||
|
url = https://github.com/dschmidt/libcrashreporter-qt
|
94
.reuse/dep5
94
.reuse/dep5
@ -1,94 +0,0 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: Calamares
|
|
||||||
Source: https://github.com/calamares/calamares.git
|
|
||||||
|
|
||||||
### ACTUAL LICENSES
|
|
||||||
#
|
|
||||||
# Images in the locale module are a bit unclear; they were added
|
|
||||||
# by Teo in 2014 but I suspect they came from somewhere else.
|
|
||||||
#
|
|
||||||
Files: src/modules/locale/images/timezone*.png
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
|
|
||||||
Files: man/calamares.8
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2017 Jonathan Carter <jcarter@linux.com>
|
|
||||||
|
|
||||||
Files: 3rdparty/kdsingleapplication/*
|
|
||||||
License: MIT
|
|
||||||
Copyright: Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@ kdab.com
|
|
||||||
|
|
||||||
### BUILD ARTIFACTS / NOT SOURCE
|
|
||||||
#
|
|
||||||
# QRC Files are basically build artifacts
|
|
||||||
#
|
|
||||||
FILES: src/modules/*/*.qrc
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# GitHub issue templates are not part of the source
|
|
||||||
#
|
|
||||||
Files: .github/ISSUE_TEMPLATE/*
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# GitHub actions are not part of the source
|
|
||||||
Files: .github/workflows/*.yml
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# Packaging information
|
|
||||||
#
|
|
||||||
Files: data/FreeBSD/distinfo data/FreeBSD/pkg-descr data/FreeBSD/pkg-plist
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# Example data for timezones, which is copied out of zoneinfo,
|
|
||||||
# which has this notice:
|
|
||||||
#
|
|
||||||
# This file is in the public domain, so clarified as of
|
|
||||||
# 2009-05-17 by Arthur David Olson.
|
|
||||||
#
|
|
||||||
Files: data/example-root/usr/share/zoneinfo/Zulu data/example-root/usr/share/zoneinfo/UTC data/example-root/usr/share/zoneinfo/America/New_York
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# Test data
|
|
||||||
#
|
|
||||||
# These first files are mere lists of locale identifiers
|
|
||||||
Files: src/modules/locale/tests/locale-data-neon src/modules/locale/tests/locale-data-freebsd
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
### TRANSLATIONS
|
|
||||||
#
|
|
||||||
# .desktop files and template change only with translation
|
|
||||||
#
|
|
||||||
FILES: calamares.desktop*
|
|
||||||
License: CC0-1.0
|
|
||||||
Copyright: no
|
|
||||||
|
|
||||||
# Transifex translations derive from the source, and have no
|
|
||||||
# embedded copyright information.
|
|
||||||
#
|
|
||||||
Files: lang/*.ts
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2020 Calamares authors and translators
|
|
||||||
|
|
||||||
# Translations of branding slideshow are the same
|
|
||||||
Files: src/branding/default/lang/*.ts
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2020 Calamares authors and translators
|
|
||||||
|
|
||||||
# Python translation files have some copyright information, but
|
|
||||||
# it's generally very sketchy.
|
|
||||||
#
|
|
||||||
Files: lang/python.pot
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2020 Calamares authors and translators
|
|
||||||
|
|
||||||
Files: lang/python/*/LC_MESSAGES/python.po
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Copyright: 2020 Calamares authors and translators
|
|
||||||
|
|
23
.travis.yml
23
.travis.yml
@ -1,23 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
#
|
|
||||||
language: cpp
|
|
||||||
|
|
||||||
python:
|
|
||||||
- 3.5
|
|
||||||
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
services:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
irc:
|
|
||||||
- "chat.freenode.net#manjaro"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- docker build -t calamares .
|
|
||||||
|
|
||||||
script:
|
|
||||||
- docker run -v $PWD:/src --tmpfs /build:rw,size=112M -e SRCDIR=/src -e BUILDDIR=/build calamares "/src/ci/travis.sh"
|
|
||||||
|
|
22
.tx/config
22
.tx/config
@ -1,24 +1,14 @@
|
|||||||
# SPDX-FileCopyrightText: no
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
[main]
|
[main]
|
||||||
host = https://app.transifex.com
|
host = https://www.transifex.com
|
||||||
|
|
||||||
[o:calamares:p:calamares:r:calamares]
|
[calamares.calamares-master]
|
||||||
file_filter = lang/calamares_<lang>.ts
|
file_filter = lang/calamares_<lang>.ts
|
||||||
source_file = lang/calamares_en.ts
|
source_file = lang/calamares_en.ts
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = QT
|
type = QT
|
||||||
|
|
||||||
[o:calamares:p:calamares:r:fdo]
|
[calamares.dummypythonqt]
|
||||||
file_filter = lang/desktop_<lang>.desktop
|
file_filter = src/modules/dummypythonqt/lang/<lang>/LC_MESSAGES/dummypythonqt.po
|
||||||
source_file = calamares.desktop
|
source_file = src/modules/dummypythonqt/lang/dummypythonqt.pot
|
||||||
source_lang = en
|
source_lang = en
|
||||||
type = DESKTOP
|
|
||||||
|
|
||||||
[o:calamares:p:calamares:r:python]
|
|
||||||
file_filter = lang/python/<lang>/LC_MESSAGES/python.po
|
|
||||||
source_file = lang/python.pot
|
|
||||||
source_lang = en
|
|
||||||
type = PO
|
|
||||||
|
|
||||||
|
26
3rdparty/kdsingleapplication/CMakeLists.txt
vendored
26
3rdparty/kdsingleapplication/CMakeLists.txt
vendored
@ -1,26 +0,0 @@
|
|||||||
set(KDSINGLEAPPLICATION_STATIC ON)
|
|
||||||
|
|
||||||
set(KDSINGLEAPPLICATION_SRCS kdsingleapplication.cpp kdsingleapplication_localsocket.cpp)
|
|
||||||
|
|
||||||
set(KDSINGLEAPPLICATION_INSTALLABLE_INCLUDES kdsingleapplication.h kdsingleapplication_lib.h)
|
|
||||||
|
|
||||||
set(KDSINGLEAPPLICATION_NON_INSTALLABLE_INCLUDES kdsingleapplication_localsocket_p.h)
|
|
||||||
|
|
||||||
if(KDSINGLEAPPLICATION_STATIC)
|
|
||||||
add_library(kdsingleapplication STATIC ${KDSINGLEAPPLICATION_INSTALLABLE_INCLUDES} ${KDSINGLEAPPLICATION_SRCS})
|
|
||||||
target_compile_definitions(kdsingleapplication PUBLIC KDSINGLEAPPLICATION_STATIC_BUILD)
|
|
||||||
else()
|
|
||||||
add_library(kdsingleapplication SHARED ${KDSINGLEAPPLICATION_INSTALLABLE_INCLUDES} ${KDSINGLEAPPLICATION_SRCS})
|
|
||||||
target_compile_definitions(kdsingleapplication PRIVATE KDSINGLEAPPLICATION_SHARED_BUILD)
|
|
||||||
endif()
|
|
||||||
set_target_properties( kdsingleapplication PROPERTIES AUTOMOC TRUE )
|
|
||||||
|
|
||||||
set(KDSINGLEAPPLICATION_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}/kdsingleapplication)
|
|
||||||
|
|
||||||
target_include_directories(
|
|
||||||
kdsingleapplication
|
|
||||||
PUBLIC $<INSTALL_INTERFACE:${KDSINGLEAPPLICATION_INCLUDEDIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(kdsingleapplication ${qtname}::Core ${qtname}::Network)
|
|
22
3rdparty/kdsingleapplication/LICENSE.MIT.txt
vendored
22
3rdparty/kdsingleapplication/LICENSE.MIT.txt
vendored
@ -1,22 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
123
3rdparty/kdsingleapplication/kdsingleapplication.cpp
vendored
123
3rdparty/kdsingleapplication/kdsingleapplication.cpp
vendored
@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "kdsingleapplication.h"
|
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
|
||||||
#include <QtCore/QFileInfo>
|
|
||||||
|
|
||||||
// TODO: make this pluggable.
|
|
||||||
#include "kdsingleapplication_localsocket_p.h"
|
|
||||||
|
|
||||||
// Avoiding dragging in Qt private APIs for now, so this does not inherit
|
|
||||||
// from QObjectPrivate.
|
|
||||||
class KDSingleApplicationPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit KDSingleApplicationPrivate(const QString &name, KDSingleApplication *q);
|
|
||||||
|
|
||||||
void initialize();
|
|
||||||
|
|
||||||
QString name() const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPrimaryInstance() const
|
|
||||||
{
|
|
||||||
return m_impl.isPrimaryInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendMessage(const QByteArray &message, int timeout)
|
|
||||||
{
|
|
||||||
return m_impl.sendMessage(message, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Q_DECLARE_PUBLIC(KDSingleApplication)
|
|
||||||
|
|
||||||
KDSingleApplication *q_ptr;
|
|
||||||
QString m_name;
|
|
||||||
|
|
||||||
KDSingleApplicationLocalSocket m_impl;
|
|
||||||
};
|
|
||||||
|
|
||||||
KDSingleApplicationPrivate::KDSingleApplicationPrivate(const QString &name, KDSingleApplication *q)
|
|
||||||
: q_ptr(q)
|
|
||||||
, m_name(name)
|
|
||||||
, m_impl(name)
|
|
||||||
{
|
|
||||||
if (Q_UNLIKELY(name.isEmpty()))
|
|
||||||
qFatal("KDSingleApplication requires a non-empty application name");
|
|
||||||
|
|
||||||
if (isPrimaryInstance()) {
|
|
||||||
QObject::connect(&m_impl, &KDSingleApplicationLocalSocket::messageReceived,
|
|
||||||
q, &KDSingleApplication::messageReceived);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString extractExecutableName(const QString &applicationFilePath)
|
|
||||||
{
|
|
||||||
return QFileInfo(applicationFilePath).fileName();
|
|
||||||
}
|
|
||||||
|
|
||||||
KDSingleApplication::KDSingleApplication(QObject *parent)
|
|
||||||
: KDSingleApplication(extractExecutableName(QCoreApplication::applicationFilePath()), parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
KDSingleApplication::KDSingleApplication(const QString &name, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, d_ptr(new KDSingleApplicationPrivate(name, this))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString KDSingleApplication::name() const
|
|
||||||
{
|
|
||||||
Q_D(const KDSingleApplication);
|
|
||||||
return d->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KDSingleApplication::isPrimaryInstance() const
|
|
||||||
{
|
|
||||||
Q_D(const KDSingleApplication);
|
|
||||||
return d->isPrimaryInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KDSingleApplication::sendMessage(const QByteArray &message)
|
|
||||||
{
|
|
||||||
return sendMessageWithTimeout(message, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KDSingleApplication::sendMessageWithTimeout(const QByteArray &message, int timeout)
|
|
||||||
{
|
|
||||||
Q_ASSERT(!isPrimaryInstance());
|
|
||||||
|
|
||||||
Q_D(KDSingleApplication);
|
|
||||||
return d->sendMessage(message, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
KDSingleApplication::~KDSingleApplication() = default;
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef KDSINGLEAPPLICATION_H
|
|
||||||
#define KDSINGLEAPPLICATION_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "kdsingleapplication_lib.h"
|
|
||||||
|
|
||||||
class KDSingleApplicationPrivate;
|
|
||||||
|
|
||||||
class KDSINGLEAPPLICATION_EXPORT KDSingleApplication : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(QString name READ name CONSTANT)
|
|
||||||
Q_PROPERTY(bool isPrimaryInstance READ isPrimaryInstance CONSTANT)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KDSingleApplication(QObject *parent = nullptr);
|
|
||||||
explicit KDSingleApplication(const QString &name, QObject *parent = nullptr);
|
|
||||||
~KDSingleApplication();
|
|
||||||
|
|
||||||
QString name() const;
|
|
||||||
bool isPrimaryInstance() const;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
// avoid default arguments and overloads, as they don't mix with connections
|
|
||||||
bool sendMessage(const QByteArray &message);
|
|
||||||
bool sendMessageWithTimeout(const QByteArray &message, int timeout);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void messageReceived(const QByteArray &message);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Q_DECLARE_PRIVATE(KDSingleApplication)
|
|
||||||
std::unique_ptr<KDSingleApplicationPrivate> d_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // KDSINGLEAPPLICATION_H
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef KDSINGLEAPPLICATION_LIB_H
|
|
||||||
#define KDSINGLEAPPLICATION_LIB_H
|
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
|
||||||
|
|
||||||
#if defined(KDSINGLEAPPLICATION_STATIC_BUILD)
|
|
||||||
#define KDSINGLEAPPLICATION_EXPORT
|
|
||||||
#elif defined(KDSINGLEAPPLICATION_SHARED_BUILD)
|
|
||||||
#define KDSINGLEAPPLICATION_EXPORT Q_DECL_EXPORT
|
|
||||||
#else
|
|
||||||
#define KDSINGLEAPPLICATION_EXPORT Q_DECL_IMPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // KDSINGLEAPPLICATION_LIB_H
|
|
@ -1,304 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "kdsingleapplication_localsocket_p.h"
|
|
||||||
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
#include <QtCore/QDeadlineTimer>
|
|
||||||
#include <QtCore/QTimer>
|
|
||||||
#include <QtCore/QLockFile>
|
|
||||||
#include <QtCore/QDataStream>
|
|
||||||
|
|
||||||
#include <QtCore/QtDebug>
|
|
||||||
#include <QtCore/QLoggingCategory>
|
|
||||||
|
|
||||||
#include <QtNetwork/QLocalServer>
|
|
||||||
#include <QtNetwork/QLocalSocket>
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#if defined(Q_OS_UNIX)
|
|
||||||
// for ::getuid()
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
#include <qt_windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const auto LOCALSOCKET_CONNECTION_TIMEOUT = std::chrono::seconds(5);
|
|
||||||
static const char LOCALSOCKET_PROTOCOL_VERSION = 2;
|
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(kdsaLocalSocket, "kdsingleapplication.localsocket", QtWarningMsg);
|
|
||||||
|
|
||||||
KDSingleApplicationLocalSocket::KDSingleApplicationLocalSocket(const QString &name, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_UNIX)
|
|
||||||
m_socketName = QStringLiteral("kdsingleapp-%1-%2-%3")
|
|
||||||
.arg(::getuid())
|
|
||||||
.arg(qEnvironmentVariable("XDG_SESSION_ID"), name);
|
|
||||||
#elif defined(Q_OS_WIN)
|
|
||||||
// I'm not sure of a "global session identifier" on Windows; are
|
|
||||||
// multiple logins from the same user a possibility? For now, following this:
|
|
||||||
// https://docs.microsoft.com/en-us/windows/desktop/devnotes/getting-the-session-id-of-the-current-process
|
|
||||||
|
|
||||||
DWORD sessionId;
|
|
||||||
BOOL haveSessionId = ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
|
||||||
|
|
||||||
m_socketName = QString::fromUtf8("kdsingleapp-%1-%2")
|
|
||||||
.arg(haveSessionId ? sessionId : 0)
|
|
||||||
.arg(name);
|
|
||||||
#else
|
|
||||||
#error "KDSingleApplication has not been ported to this platform"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const QString lockFilePath =
|
|
||||||
QDir::tempPath() + QLatin1Char('/') + m_socketName + QLatin1String(".lock");
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Socket name is" << m_socketName;
|
|
||||||
qCDebug(kdsaLocalSocket) << "Lock file path is" << lockFilePath;
|
|
||||||
|
|
||||||
std::unique_ptr<QLockFile> lockFile(new QLockFile(lockFilePath));
|
|
||||||
lockFile->setStaleLockTime(0);
|
|
||||||
|
|
||||||
if (!lockFile->tryLock()) {
|
|
||||||
// someone else has the lock => we're secondary
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<QLocalServer> server = std::make_unique<QLocalServer>();
|
|
||||||
if (!server->listen(m_socketName)) {
|
|
||||||
// maybe the primary crashed, leaving a stale socket; delete it and try again
|
|
||||||
QLocalServer::removeServer(m_socketName);
|
|
||||||
if (!server->listen(m_socketName)) {
|
|
||||||
// TODO: better error handling.
|
|
||||||
qWarning("KDSingleApplication: unable to make the primary instance listen on %ls: %ls",
|
|
||||||
qUtf16Printable(m_socketName),
|
|
||||||
qUtf16Printable(server->errorString()));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(server.get(), &QLocalServer::newConnection,
|
|
||||||
this, &KDSingleApplicationLocalSocket::handleNewConnection);
|
|
||||||
|
|
||||||
m_lockFile = std::move(lockFile);
|
|
||||||
m_localServer = std::move(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
KDSingleApplicationLocalSocket::~KDSingleApplicationLocalSocket() = default;
|
|
||||||
|
|
||||||
bool KDSingleApplicationLocalSocket::isPrimaryInstance() const
|
|
||||||
{
|
|
||||||
return m_localServer != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KDSingleApplicationLocalSocket::sendMessage(const QByteArray &message, int timeout)
|
|
||||||
{
|
|
||||||
Q_ASSERT(!isPrimaryInstance());
|
|
||||||
QLocalSocket socket;
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Preparing to send message" << message << "with timeout" << timeout;
|
|
||||||
|
|
||||||
QDeadlineTimer deadline(timeout);
|
|
||||||
|
|
||||||
// There is an inherent race here with the setup of the server side.
|
|
||||||
// Even if the socket lock is held by the server, the server may not
|
|
||||||
// be listening yet. So this connection may fail; keep retrying
|
|
||||||
// until we hit the timeout.
|
|
||||||
do {
|
|
||||||
socket.connectToServer(m_socketName);
|
|
||||||
if (socket.waitForConnected(deadline.remainingTime()))
|
|
||||||
break;
|
|
||||||
} while (!deadline.hasExpired());
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Socket state:" << socket.state() << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
|
|
||||||
|
|
||||||
if (deadline.hasExpired())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
socket.write(&LOCALSOCKET_PROTOCOL_VERSION, 1);
|
|
||||||
|
|
||||||
{
|
|
||||||
QByteArray encodedMessage;
|
|
||||||
QDataStream ds(&encodedMessage, QIODevice::WriteOnly);
|
|
||||||
ds << message;
|
|
||||||
socket.write(encodedMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Wrote message in the socket" << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
|
|
||||||
|
|
||||||
// There is no acknowledgement mechanism here.
|
|
||||||
// Should there be one?
|
|
||||||
|
|
||||||
while (socket.bytesToWrite() > 0) {
|
|
||||||
if (!socket.waitForBytesWritten(deadline.remainingTime()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Bytes written, now disconnecting" << "Timer remaining" << deadline.remainingTime() << "Expired?" << deadline.hasExpired();
|
|
||||||
|
|
||||||
socket.disconnectFromServer();
|
|
||||||
|
|
||||||
if (socket.state() == QLocalSocket::UnconnectedState)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!socket.waitForDisconnected(deadline.remainingTime()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Disconnected -- success!";
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KDSingleApplicationLocalSocket::handleNewConnection()
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_localServer);
|
|
||||||
|
|
||||||
QLocalSocket *socket = m_localServer->nextPendingConnection();
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Got new connection on" << m_socketName << "state" << socket->state();
|
|
||||||
|
|
||||||
Connection c(socket);
|
|
||||||
|
|
||||||
c.readDataConnection = QObjectConnectionHolder(
|
|
||||||
connect(c.socket.get(), &QLocalSocket::readyRead,
|
|
||||||
this, &KDSingleApplicationLocalSocket::readDataFromSecondary));
|
|
||||||
|
|
||||||
c.secondaryDisconnectedConnection = QObjectConnectionHolder(
|
|
||||||
connect(c.socket.get(), &QLocalSocket::disconnected,
|
|
||||||
this, &KDSingleApplicationLocalSocket::secondaryDisconnected));
|
|
||||||
|
|
||||||
c.abortConnection = QObjectConnectionHolder(
|
|
||||||
connect(c.timeoutTimer.get(), &QTimer::timeout,
|
|
||||||
this, &KDSingleApplicationLocalSocket::abortConnectionToSecondary));
|
|
||||||
|
|
||||||
m_clients.push_back(std::move(c));
|
|
||||||
|
|
||||||
// Note that by the time we get here, the socket could've already been closed,
|
|
||||||
// and no signals emitted (hello, Windows!). Read what's already in the socket.
|
|
||||||
if (readDataFromSecondarySocket(socket))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (socket->state() == QLocalSocket::UnconnectedState)
|
|
||||||
secondarySocketDisconnected(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Container>
|
|
||||||
static auto findConnectionBySocket(Container &container, QLocalSocket *socket)
|
|
||||||
{
|
|
||||||
auto i = std::find_if(container.begin(),
|
|
||||||
container.end(),
|
|
||||||
[socket](const auto &c) { return c.socket.get() == socket; });
|
|
||||||
Q_ASSERT(i != container.end());
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Container>
|
|
||||||
static auto findConnectionByTimer(Container &container, QTimer *timer)
|
|
||||||
{
|
|
||||||
auto i = std::find_if(container.begin(),
|
|
||||||
container.end(),
|
|
||||||
[timer](const auto &c) { return c.timeoutTimer.get() == timer; });
|
|
||||||
Q_ASSERT(i != container.end());
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KDSingleApplicationLocalSocket::readDataFromSecondary()
|
|
||||||
{
|
|
||||||
QLocalSocket *socket = static_cast<QLocalSocket *>(sender());
|
|
||||||
readDataFromSecondarySocket(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KDSingleApplicationLocalSocket::readDataFromSecondarySocket(QLocalSocket *socket)
|
|
||||||
{
|
|
||||||
auto i = findConnectionBySocket(m_clients, socket);
|
|
||||||
Connection &c = *i;
|
|
||||||
c.readData.append(socket->readAll());
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Got more data from a secondary. Data read so far:" << c.readData;
|
|
||||||
|
|
||||||
const QByteArray &data = c.readData;
|
|
||||||
|
|
||||||
if (data.size() >= 1) {
|
|
||||||
if (data[0] != LOCALSOCKET_PROTOCOL_VERSION) {
|
|
||||||
qCDebug(kdsaLocalSocket) << "Got an invalid protocol version";
|
|
||||||
m_clients.erase(i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QDataStream ds(data);
|
|
||||||
ds.skipRawData(1);
|
|
||||||
|
|
||||||
ds.startTransaction();
|
|
||||||
QByteArray message;
|
|
||||||
ds >> message;
|
|
||||||
|
|
||||||
if (ds.commitTransaction()) {
|
|
||||||
qCDebug(kdsaLocalSocket) << "Got a complete message:" << message;
|
|
||||||
Q_EMIT messageReceived(message);
|
|
||||||
m_clients.erase(i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KDSingleApplicationLocalSocket::secondaryDisconnected()
|
|
||||||
{
|
|
||||||
QLocalSocket *socket = static_cast<QLocalSocket *>(sender());
|
|
||||||
secondarySocketDisconnected(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KDSingleApplicationLocalSocket::secondarySocketDisconnected(QLocalSocket *socket)
|
|
||||||
{
|
|
||||||
auto i = findConnectionBySocket(m_clients, socket);
|
|
||||||
Connection c = std::move(*i);
|
|
||||||
m_clients.erase(i);
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Secondary disconnected. Data read:" << c.readData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KDSingleApplicationLocalSocket::abortConnectionToSecondary()
|
|
||||||
{
|
|
||||||
QTimer *timer = static_cast<QTimer *>(sender());
|
|
||||||
|
|
||||||
auto i = findConnectionByTimer(m_clients, timer);
|
|
||||||
Connection c = std::move(*i);
|
|
||||||
m_clients.erase(i);
|
|
||||||
|
|
||||||
qCDebug(kdsaLocalSocket) << "Secondary timed out. Data read:" << c.readData;
|
|
||||||
}
|
|
||||||
|
|
||||||
KDSingleApplicationLocalSocket::Connection::Connection(QLocalSocket *socket)
|
|
||||||
: socket(socket)
|
|
||||||
, timeoutTimer(new QTimer)
|
|
||||||
{
|
|
||||||
timeoutTimer->start(LOCALSOCKET_CONNECTION_TIMEOUT);
|
|
||||||
}
|
|
@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (C) 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef KDSINGLEAPPLICATION_LOCALSOCKET_P_H
|
|
||||||
#define KDSINGLEAPPLICATION_LOCALSOCKET_P_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QLockFile;
|
|
||||||
class QLocalServer;
|
|
||||||
class QLocalSocket;
|
|
||||||
class QTimer;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct QObjectDeleteLater
|
|
||||||
{
|
|
||||||
void operator()(QObject *o) { o->deleteLater(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class QObjectConnectionHolder
|
|
||||||
{
|
|
||||||
Q_DISABLE_COPY(QObjectConnectionHolder)
|
|
||||||
QMetaObject::Connection c;
|
|
||||||
|
|
||||||
public:
|
|
||||||
QObjectConnectionHolder() {}
|
|
||||||
|
|
||||||
explicit QObjectConnectionHolder(QMetaObject::Connection c)
|
|
||||||
: c(std::move(c))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~QObjectConnectionHolder()
|
|
||||||
{
|
|
||||||
QObject::disconnect(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
QObjectConnectionHolder(QObjectConnectionHolder &&other) noexcept
|
|
||||||
: c(std::exchange(other.c, {}))
|
|
||||||
{}
|
|
||||||
|
|
||||||
QObjectConnectionHolder &operator=(QObjectConnectionHolder &&other) noexcept
|
|
||||||
{
|
|
||||||
QObjectConnectionHolder moved(std::move(other));
|
|
||||||
swap(moved);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(QObjectConnectionHolder &other) noexcept
|
|
||||||
{
|
|
||||||
using std::swap;
|
|
||||||
swap(c, other.c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class KDSingleApplicationLocalSocket : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KDSingleApplicationLocalSocket(const QString &name,
|
|
||||||
QObject *parent = nullptr);
|
|
||||||
~KDSingleApplicationLocalSocket();
|
|
||||||
|
|
||||||
bool isPrimaryInstance() const;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
bool sendMessage(const QByteArray &message, int timeout);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void messageReceived(const QByteArray &message);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void handleNewConnection();
|
|
||||||
void readDataFromSecondary();
|
|
||||||
bool readDataFromSecondarySocket(QLocalSocket *socket);
|
|
||||||
void secondaryDisconnected();
|
|
||||||
void secondarySocketDisconnected(QLocalSocket *socket);
|
|
||||||
void abortConnectionToSecondary();
|
|
||||||
|
|
||||||
QString m_socketName;
|
|
||||||
|
|
||||||
std::unique_ptr<QLockFile> m_lockFile; // protects m_localServer
|
|
||||||
std::unique_ptr<QLocalServer> m_localServer;
|
|
||||||
|
|
||||||
struct Connection {
|
|
||||||
explicit Connection(QLocalSocket *s);
|
|
||||||
|
|
||||||
std::unique_ptr<QLocalSocket, QObjectDeleteLater> socket;
|
|
||||||
std::unique_ptr<QTimer, QObjectDeleteLater> timeoutTimer;
|
|
||||||
QByteArray readData;
|
|
||||||
|
|
||||||
// socket/timeoutTimer are deleted via deleteLater (as we delete them
|
|
||||||
// in slots connected to their signals). Before the deleteLater is acted upon,
|
|
||||||
// they may emit further signals, triggering logic that it's not supposed
|
|
||||||
// to be triggered (as the Connection has already been destroyed).
|
|
||||||
// Use this Holder to break the connections.
|
|
||||||
QObjectConnectionHolder readDataConnection;
|
|
||||||
QObjectConnectionHolder secondaryDisconnectedConnection;
|
|
||||||
QObjectConnectionHolder abortConnection;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Connection> m_clients;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // KDSINGLEAPPLICATION_LOCALSOCKET_P_H
|
|
20
3rdparty/kdsingleapplication/src.pro
vendored
20
3rdparty/kdsingleapplication/src.pro
vendored
@ -1,20 +0,0 @@
|
|||||||
include(../common.pri)
|
|
||||||
|
|
||||||
TEMPLATE = lib
|
|
||||||
TARGET = kdsingleapplication
|
|
||||||
QT = core network
|
|
||||||
CONFIG += static
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
kdsingleapplication.cpp \
|
|
||||||
kdsingleapplication_localsocket.cpp \
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
kdsingleapplication.h \
|
|
||||||
kdsingleapplication_lib.h \
|
|
||||||
kdsingleapplication_localsocket_p.h \
|
|
||||||
|
|
||||||
DEFINES += \
|
|
||||||
KDSINGLEAPPLICATION_BUILD
|
|
||||||
|
|
||||||
win32:LIBS += -lkernel32
|
|
16
3rdparty/pybind11/CMakeLists.txt
vendored
16
3rdparty/pybind11/CMakeLists.txt
vendored
@ -1,16 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2023 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This is a very-stripped-down way of getting the bundled pybind11
|
|
||||||
|
|
||||||
add_library(pybind11_headers INTERFACE)
|
|
||||||
add_library(pybind11::headers ALIAS pybind11_headers)
|
|
||||||
|
|
||||||
target_include_directories(pybind11_headers INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
target_link_libraries(pybind11_headers INTERFACE Python::Python) # Was searched-for at top-level
|
|
||||||
|
|
||||||
|
|
29
3rdparty/pybind11/LICENSE
vendored
29
3rdparty/pybind11/LICENSE
vendored
@ -1,29 +0,0 @@
|
|||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
|
|
||||||
external contributions to this project including patches, pull requests, etc.
|
|
6
3rdparty/pybind11/MANIFEST.in
vendored
6
3rdparty/pybind11/MANIFEST.in
vendored
@ -1,6 +0,0 @@
|
|||||||
prune tests
|
|
||||||
recursive-include pybind11/include/pybind11 *.h
|
|
||||||
recursive-include pybind11 *.py
|
|
||||||
recursive-include pybind11 py.typed
|
|
||||||
include pybind11/share/cmake/pybind11/*.cmake
|
|
||||||
include LICENSE README.rst SECURITY.md pyproject.toml setup.py setup.cfg
|
|
180
3rdparty/pybind11/README.rst
vendored
180
3rdparty/pybind11/README.rst
vendored
@ -1,180 +0,0 @@
|
|||||||
.. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png
|
|
||||||
:alt: pybind11 logo
|
|
||||||
|
|
||||||
**pybind11 — Seamless operability between C++11 and Python**
|
|
||||||
|
|
||||||
|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status|
|
|
||||||
|
|
||||||
|Repology| |PyPI package| |Conda-forge| |Python Versions|
|
|
||||||
|
|
||||||
`Setuptools example <https://github.com/pybind/python_example>`_
|
|
||||||
• `Scikit-build example <https://github.com/pybind/scikit_build_example>`_
|
|
||||||
• `CMake example <https://github.com/pybind/cmake_example>`_
|
|
||||||
|
|
||||||
.. start
|
|
||||||
|
|
||||||
|
|
||||||
**pybind11** is a lightweight header-only library that exposes C++ types
|
|
||||||
in Python and vice versa, mainly to create Python bindings of existing
|
|
||||||
C++ code. Its goals and syntax are similar to the excellent
|
|
||||||
`Boost.Python <http://www.boost.org/doc/libs/1_58_0/libs/python/doc/>`_
|
|
||||||
library by David Abrahams: to minimize boilerplate code in traditional
|
|
||||||
extension modules by inferring type information using compile-time
|
|
||||||
introspection.
|
|
||||||
|
|
||||||
The main issue with Boost.Python—and the reason for creating such a
|
|
||||||
similar project—is Boost. Boost is an enormously large and complex suite
|
|
||||||
of utility libraries that works with almost every C++ compiler in
|
|
||||||
existence. This compatibility has its cost: arcane template tricks and
|
|
||||||
workarounds are necessary to support the oldest and buggiest of compiler
|
|
||||||
specimens. Now that C++11-compatible compilers are widely available,
|
|
||||||
this heavy machinery has become an excessively large and unnecessary
|
|
||||||
dependency.
|
|
||||||
|
|
||||||
Think of this library as a tiny self-contained version of Boost.Python
|
|
||||||
with everything stripped away that isn't relevant for binding
|
|
||||||
generation. Without comments, the core header files only require ~4K
|
|
||||||
lines of code and depend on Python (3.6+, or PyPy) and the C++
|
|
||||||
standard library. This compact implementation was possible thanks to
|
|
||||||
some of the new C++11 language features (specifically: tuples, lambda
|
|
||||||
functions and variadic templates). Since its creation, this library has
|
|
||||||
grown beyond Boost.Python in many ways, leading to dramatically simpler
|
|
||||||
binding code in many common situations.
|
|
||||||
|
|
||||||
Tutorial and reference documentation is provided at
|
|
||||||
`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.
|
|
||||||
A PDF version of the manual is available
|
|
||||||
`here <https://pybind11.readthedocs.io/_/downloads/en/latest/pdf/>`_.
|
|
||||||
And the source code is always available at
|
|
||||||
`github.com/pybind/pybind11 <https://github.com/pybind/pybind11>`_.
|
|
||||||
|
|
||||||
|
|
||||||
Core features
|
|
||||||
-------------
|
|
||||||
|
|
||||||
|
|
||||||
pybind11 can map the following core C++ features to Python:
|
|
||||||
|
|
||||||
- Functions accepting and returning custom data structures per value,
|
|
||||||
reference, or pointer
|
|
||||||
- Instance methods and static methods
|
|
||||||
- Overloaded functions
|
|
||||||
- Instance attributes and static attributes
|
|
||||||
- Arbitrary exception types
|
|
||||||
- Enumerations
|
|
||||||
- Callbacks
|
|
||||||
- Iterators and ranges
|
|
||||||
- Custom operators
|
|
||||||
- Single and multiple inheritance
|
|
||||||
- STL data structures
|
|
||||||
- Smart pointers with reference counting like ``std::shared_ptr``
|
|
||||||
- Internal references with correct reference counting
|
|
||||||
- C++ classes with virtual (and pure virtual) methods can be extended
|
|
||||||
in Python
|
|
||||||
|
|
||||||
Goodies
|
|
||||||
-------
|
|
||||||
|
|
||||||
In addition to the core functionality, pybind11 provides some extra
|
|
||||||
goodies:
|
|
||||||
|
|
||||||
- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic
|
|
||||||
interface (pybind11 2.9 was the last version to support Python 2 and 3.5).
|
|
||||||
|
|
||||||
- It is possible to bind C++11 lambda functions with captured
|
|
||||||
variables. The lambda capture data is stored inside the resulting
|
|
||||||
Python function object.
|
|
||||||
|
|
||||||
- pybind11 uses C++11 move constructors and move assignment operators
|
|
||||||
whenever possible to efficiently transfer custom data types.
|
|
||||||
|
|
||||||
- It's easy to expose the internal storage of custom data types through
|
|
||||||
Pythons' buffer protocols. This is handy e.g. for fast conversion
|
|
||||||
between C++ matrix classes like Eigen and NumPy without expensive
|
|
||||||
copy operations.
|
|
||||||
|
|
||||||
- pybind11 can automatically vectorize functions so that they are
|
|
||||||
transparently applied to all entries of one or more NumPy array
|
|
||||||
arguments.
|
|
||||||
|
|
||||||
- Python's slice-based access and assignment operations can be
|
|
||||||
supported with just a few lines of code.
|
|
||||||
|
|
||||||
- Everything is contained in just a few header files; there is no need
|
|
||||||
to link against any additional libraries.
|
|
||||||
|
|
||||||
- Binaries are generally smaller by a factor of at least 2 compared to
|
|
||||||
equivalent bindings generated by Boost.Python. A recent pybind11
|
|
||||||
conversion of PyRosetta, an enormous Boost.Python binding project,
|
|
||||||
`reported <https://graylab.jhu.edu/Sergey/2016.RosettaCon/PyRosetta-4.pdf>`_
|
|
||||||
a binary size reduction of **5.4x** and compile time reduction by
|
|
||||||
**5.8x**.
|
|
||||||
|
|
||||||
- Function signatures are precomputed at compile time (using
|
|
||||||
``constexpr``), leading to smaller binaries.
|
|
||||||
|
|
||||||
- With little extra effort, C++ types can be pickled and unpickled
|
|
||||||
similar to regular Python objects.
|
|
||||||
|
|
||||||
Supported compilers
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or
|
|
||||||
newer)
|
|
||||||
2. GCC 4.8 or newer
|
|
||||||
3. Microsoft Visual Studio 2017 or newer
|
|
||||||
4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)
|
|
||||||
5. Cygwin/GCC (previously tested on 2.5.1)
|
|
||||||
6. NVCC (CUDA 11.0 tested in CI)
|
|
||||||
7. NVIDIA PGI (20.9 tested in CI)
|
|
||||||
|
|
||||||
About
|
|
||||||
-----
|
|
||||||
|
|
||||||
This project was created by `Wenzel
|
|
||||||
Jakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or
|
|
||||||
improvements to the code were contributed by Jonas Adler, Lori A. Burns,
|
|
||||||
Sylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel
|
|
||||||
Huebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko,
|
|
||||||
Dean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim
|
|
||||||
Schellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.
|
|
||||||
|
|
||||||
We thank Google for a generous financial contribution to the continuous
|
|
||||||
integration infrastructure used by this project.
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
See the `contributing
|
|
||||||
guide <https://github.com/pybind/pybind11/blob/master/.github/CONTRIBUTING.md>`_
|
|
||||||
for information on building and contributing to pybind11.
|
|
||||||
|
|
||||||
License
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
pybind11 is provided under a BSD-style license that can be found in the
|
|
||||||
`LICENSE <https://github.com/pybind/pybind11/blob/master/LICENSE>`_
|
|
||||||
file. By using, distributing, or contributing to this project, you agree
|
|
||||||
to the terms and conditions of this license.
|
|
||||||
|
|
||||||
.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest
|
|
||||||
:target: http://pybind11.readthedocs.org/en/latest
|
|
||||||
.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg
|
|
||||||
:target: http://pybind11.readthedocs.org/en/stable
|
|
||||||
.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg
|
|
||||||
:target: https://gitter.im/pybind/Lobby
|
|
||||||
.. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg
|
|
||||||
:target: https://github.com/pybind/pybind11/actions
|
|
||||||
.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true
|
|
||||||
:target: https://ci.appveyor.com/project/wjakob/pybind11
|
|
||||||
.. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg
|
|
||||||
:target: https://pypi.org/project/pybind11/
|
|
||||||
.. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg
|
|
||||||
:target: https://github.com/conda-forge/pybind11-feedstock
|
|
||||||
.. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg
|
|
||||||
:target: https://repology.org/project/python:pybind11/versions
|
|
||||||
.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg
|
|
||||||
:target: https://pypi.org/project/pybind11/
|
|
||||||
.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
|
|
||||||
:target: https://github.com/pybind/pybind11/discussions
|
|
13
3rdparty/pybind11/SECURITY.md
vendored
13
3rdparty/pybind11/SECURITY.md
vendored
@ -1,13 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
Security updates are applied only to the latest release.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
|
|
||||||
|
|
||||||
Please disclose it at [security advisory](https://github.com/pybind/pybind11/security/advisories/new).
|
|
||||||
|
|
||||||
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
|
|
690
3rdparty/pybind11/include/pybind11/attr.h
vendored
690
3rdparty/pybind11/include/pybind11/attr.h
vendored
@ -1,690 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/attr.h: Infrastructure for processing custom
|
|
||||||
type and function attributes
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
#include "cast.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
/// \addtogroup annotations
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
/// Annotation for methods
|
|
||||||
struct is_method {
|
|
||||||
handle class_;
|
|
||||||
explicit is_method(const handle &c) : class_(c) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation for setters
|
|
||||||
struct is_setter {};
|
|
||||||
|
|
||||||
/// Annotation for operators
|
|
||||||
struct is_operator {};
|
|
||||||
|
|
||||||
/// Annotation for classes that cannot be subclassed
|
|
||||||
struct is_final {};
|
|
||||||
|
|
||||||
/// Annotation for parent scope
|
|
||||||
struct scope {
|
|
||||||
handle value;
|
|
||||||
explicit scope(const handle &s) : value(s) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation for documentation
|
|
||||||
struct doc {
|
|
||||||
const char *value;
|
|
||||||
explicit doc(const char *value) : value(value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation for function names
|
|
||||||
struct name {
|
|
||||||
const char *value;
|
|
||||||
explicit name(const char *value) : value(value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation indicating that a function is an overload associated with a given "sibling"
|
|
||||||
struct sibling {
|
|
||||||
handle value;
|
|
||||||
explicit sibling(const handle &value) : value(value.ptr()) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation indicating that a class derives from another given type
|
|
||||||
template <typename T>
|
|
||||||
struct base {
|
|
||||||
|
|
||||||
PYBIND11_DEPRECATED(
|
|
||||||
"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
|
||||||
base() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Keep patient alive while nurse lives
|
|
||||||
template <size_t Nurse, size_t Patient>
|
|
||||||
struct keep_alive {};
|
|
||||||
|
|
||||||
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
|
||||||
struct multiple_inheritance {};
|
|
||||||
|
|
||||||
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
|
|
||||||
struct dynamic_attr {};
|
|
||||||
|
|
||||||
/// Annotation which enables the buffer protocol for a type
|
|
||||||
struct buffer_protocol {};
|
|
||||||
|
|
||||||
/// Annotation which requests that a special metaclass is created for a type
|
|
||||||
struct metaclass {
|
|
||||||
handle value;
|
|
||||||
|
|
||||||
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
|
|
||||||
metaclass() = default;
|
|
||||||
|
|
||||||
/// Override pybind11's default metaclass
|
|
||||||
explicit metaclass(handle value) : value(value) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that
|
|
||||||
/// may be used to customize the Python type.
|
|
||||||
///
|
|
||||||
/// The callback is invoked immediately before `PyType_Ready`.
|
|
||||||
///
|
|
||||||
/// Note: This is an advanced interface, and uses of it may require changes to
|
|
||||||
/// work with later versions of pybind11. You may wish to consult the
|
|
||||||
/// implementation of `make_new_python_type` in `detail/classes.h` to understand
|
|
||||||
/// the context in which the callback will be run.
|
|
||||||
struct custom_type_setup {
|
|
||||||
using callback = std::function<void(PyHeapTypeObject *heap_type)>;
|
|
||||||
|
|
||||||
explicit custom_type_setup(callback value) : value(std::move(value)) {}
|
|
||||||
|
|
||||||
callback value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation that marks a class as local to the module:
|
|
||||||
struct module_local {
|
|
||||||
const bool value;
|
|
||||||
constexpr explicit module_local(bool v = true) : value(v) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Annotation to mark enums as an arithmetic type
|
|
||||||
struct arithmetic {};
|
|
||||||
|
|
||||||
/// Mark a function for addition at the beginning of the existing overload chain instead of the end
|
|
||||||
struct prepend {};
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
A call policy which places one or more guard variables (``Ts...``) around the function call.
|
|
||||||
|
|
||||||
For example, this definition:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
m.def("foo", foo, py::call_guard<T>());
|
|
||||||
|
|
||||||
is equivalent to the following pseudocode:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
m.def("foo", [](args...) {
|
|
||||||
T scope_guard;
|
|
||||||
return foo(args...); // forwarded arguments
|
|
||||||
});
|
|
||||||
\endrst */
|
|
||||||
template <typename... Ts>
|
|
||||||
struct call_guard;
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct call_guard<> {
|
|
||||||
using type = detail::void_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct call_guard<T> {
|
|
||||||
static_assert(std::is_default_constructible<T>::value,
|
|
||||||
"The guard type must be default constructible");
|
|
||||||
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
|
||||||
struct call_guard<T, Ts...> {
|
|
||||||
struct type {
|
|
||||||
T guard{}; // Compose multiple guard types with left-to-right default-constructor order
|
|
||||||
typename call_guard<Ts...>::type next{};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @} annotations
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
/* Forward declarations */
|
|
||||||
enum op_id : int;
|
|
||||||
enum op_type : int;
|
|
||||||
struct undefined_t;
|
|
||||||
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>
|
|
||||||
struct op_;
|
|
||||||
void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
|
|
||||||
|
|
||||||
/// Internal data structure which holds metadata about a keyword argument
|
|
||||||
struct argument_record {
|
|
||||||
const char *name; ///< Argument name
|
|
||||||
const char *descr; ///< Human-readable version of the argument value
|
|
||||||
handle value; ///< Associated Python object
|
|
||||||
bool convert : 1; ///< True if the argument is allowed to convert when loading
|
|
||||||
bool none : 1; ///< True if None is allowed when loading
|
|
||||||
|
|
||||||
argument_record(const char *name, const char *descr, handle value, bool convert, bool none)
|
|
||||||
: name(name), descr(descr), value(value), convert(convert), none(none) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Internal data structure which holds metadata about a bound function (signature, overloads,
|
|
||||||
/// etc.)
|
|
||||||
struct function_record {
|
|
||||||
function_record()
|
|
||||||
: is_constructor(false), is_new_style_constructor(false), is_stateless(false),
|
|
||||||
is_operator(false), is_method(false), is_setter(false), has_args(false),
|
|
||||||
has_kwargs(false), prepend(false) {}
|
|
||||||
|
|
||||||
/// Function name
|
|
||||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
|
||||||
|
|
||||||
// User-specified documentation string
|
|
||||||
char *doc = nullptr;
|
|
||||||
|
|
||||||
/// Human-readable version of the function signature
|
|
||||||
char *signature = nullptr;
|
|
||||||
|
|
||||||
/// List of registered keyword arguments
|
|
||||||
std::vector<argument_record> args;
|
|
||||||
|
|
||||||
/// Pointer to lambda function which converts arguments and performs the actual call
|
|
||||||
handle (*impl)(function_call &) = nullptr;
|
|
||||||
|
|
||||||
/// Storage for the wrapped function pointer and captured data, if any
|
|
||||||
void *data[3] = {};
|
|
||||||
|
|
||||||
/// Pointer to custom destructor for 'data' (if needed)
|
|
||||||
void (*free_data)(function_record *ptr) = nullptr;
|
|
||||||
|
|
||||||
/// Return value policy associated with this function
|
|
||||||
return_value_policy policy = return_value_policy::automatic;
|
|
||||||
|
|
||||||
/// True if name == '__init__'
|
|
||||||
bool is_constructor : 1;
|
|
||||||
|
|
||||||
/// True if this is a new-style `__init__` defined in `detail/init.h`
|
|
||||||
bool is_new_style_constructor : 1;
|
|
||||||
|
|
||||||
/// True if this is a stateless function pointer
|
|
||||||
bool is_stateless : 1;
|
|
||||||
|
|
||||||
/// True if this is an operator (__add__), etc.
|
|
||||||
bool is_operator : 1;
|
|
||||||
|
|
||||||
/// True if this is a method
|
|
||||||
bool is_method : 1;
|
|
||||||
|
|
||||||
/// True if this is a setter
|
|
||||||
bool is_setter : 1;
|
|
||||||
|
|
||||||
/// True if the function has a '*args' argument
|
|
||||||
bool has_args : 1;
|
|
||||||
|
|
||||||
/// True if the function has a '**kwargs' argument
|
|
||||||
bool has_kwargs : 1;
|
|
||||||
|
|
||||||
/// True if this function is to be inserted at the beginning of the overload resolution chain
|
|
||||||
bool prepend : 1;
|
|
||||||
|
|
||||||
/// Number of arguments (including py::args and/or py::kwargs, if present)
|
|
||||||
std::uint16_t nargs;
|
|
||||||
|
|
||||||
/// Number of leading positional arguments, which are terminated by a py::args or py::kwargs
|
|
||||||
/// argument or by a py::kw_only annotation.
|
|
||||||
std::uint16_t nargs_pos = 0;
|
|
||||||
|
|
||||||
/// Number of leading arguments (counted in `nargs`) that are positional-only
|
|
||||||
std::uint16_t nargs_pos_only = 0;
|
|
||||||
|
|
||||||
/// Python method object
|
|
||||||
PyMethodDef *def = nullptr;
|
|
||||||
|
|
||||||
/// Python handle to the parent scope (a class or a module)
|
|
||||||
handle scope;
|
|
||||||
|
|
||||||
/// Python handle to the sibling function representing an overload chain
|
|
||||||
handle sibling;
|
|
||||||
|
|
||||||
/// Pointer to next overload
|
|
||||||
function_record *next = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Special data structure which (temporarily) holds metadata about a bound class
|
|
||||||
struct type_record {
|
|
||||||
PYBIND11_NOINLINE type_record()
|
|
||||||
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),
|
|
||||||
default_holder(true), module_local(false), is_final(false) {}
|
|
||||||
|
|
||||||
/// Handle to the parent scope
|
|
||||||
handle scope;
|
|
||||||
|
|
||||||
/// Name of the class
|
|
||||||
const char *name = nullptr;
|
|
||||||
|
|
||||||
// Pointer to RTTI type_info data structure
|
|
||||||
const std::type_info *type = nullptr;
|
|
||||||
|
|
||||||
/// How large is the underlying C++ type?
|
|
||||||
size_t type_size = 0;
|
|
||||||
|
|
||||||
/// What is the alignment of the underlying C++ type?
|
|
||||||
size_t type_align = 0;
|
|
||||||
|
|
||||||
/// How large is the type's holder?
|
|
||||||
size_t holder_size = 0;
|
|
||||||
|
|
||||||
/// The global operator new can be overridden with a class-specific variant
|
|
||||||
void *(*operator_new)(size_t) = nullptr;
|
|
||||||
|
|
||||||
/// Function pointer to class_<..>::init_instance
|
|
||||||
void (*init_instance)(instance *, const void *) = nullptr;
|
|
||||||
|
|
||||||
/// Function pointer to class_<..>::dealloc
|
|
||||||
void (*dealloc)(detail::value_and_holder &) = nullptr;
|
|
||||||
|
|
||||||
/// List of base classes of the newly created type
|
|
||||||
list bases;
|
|
||||||
|
|
||||||
/// Optional docstring
|
|
||||||
const char *doc = nullptr;
|
|
||||||
|
|
||||||
/// Custom metaclass (optional)
|
|
||||||
handle metaclass;
|
|
||||||
|
|
||||||
/// Custom type setup.
|
|
||||||
custom_type_setup::callback custom_type_setup_callback;
|
|
||||||
|
|
||||||
/// Multiple inheritance marker
|
|
||||||
bool multiple_inheritance : 1;
|
|
||||||
|
|
||||||
/// Does the class manage a __dict__?
|
|
||||||
bool dynamic_attr : 1;
|
|
||||||
|
|
||||||
/// Does the class implement the buffer protocol?
|
|
||||||
bool buffer_protocol : 1;
|
|
||||||
|
|
||||||
/// Is the default (unique_ptr) holder type used?
|
|
||||||
bool default_holder : 1;
|
|
||||||
|
|
||||||
/// Is the class definition local to the module shared object?
|
|
||||||
bool module_local : 1;
|
|
||||||
|
|
||||||
/// Is the class inheritable from python classes?
|
|
||||||
bool is_final : 1;
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {
|
|
||||||
auto *base_info = detail::get_type_info(base, false);
|
|
||||||
if (!base_info) {
|
|
||||||
std::string tname(base.name());
|
|
||||||
detail::clean_type_id(tname);
|
|
||||||
pybind11_fail("generic_type: type \"" + std::string(name)
|
|
||||||
+ "\" referenced unknown base type \"" + tname + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (default_holder != base_info->default_holder) {
|
|
||||||
std::string tname(base.name());
|
|
||||||
detail::clean_type_id(tname);
|
|
||||||
pybind11_fail("generic_type: type \"" + std::string(name) + "\" "
|
|
||||||
+ (default_holder ? "does not have" : "has")
|
|
||||||
+ " a non-default holder type while its base \"" + tname + "\" "
|
|
||||||
+ (base_info->default_holder ? "does not" : "does"));
|
|
||||||
}
|
|
||||||
|
|
||||||
bases.append((PyObject *) base_info->type);
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x030B0000
|
|
||||||
dynamic_attr |= base_info->type->tp_dictoffset != 0;
|
|
||||||
#else
|
|
||||||
dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (caster) {
|
|
||||||
base_info->implicit_casts.emplace_back(type, caster);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) {
|
|
||||||
args.reserve(f.nargs);
|
|
||||||
args_convert.reserve(f.nargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tag for a new-style `__init__` defined in `detail/init.h`
|
|
||||||
struct is_new_style_constructor {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Partial template specializations to process custom attributes provided to
|
|
||||||
* cpp_function_ and class_. These are either used to initialize the respective
|
|
||||||
* fields in the type_record and function_record data structures or executed at
|
|
||||||
* runtime to deal with custom call policies (e.g. keep_alive).
|
|
||||||
*/
|
|
||||||
template <typename T, typename SFINAE = void>
|
|
||||||
struct process_attribute;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct process_attribute_default {
|
|
||||||
/// Default implementation: do nothing
|
|
||||||
static void init(const T &, function_record *) {}
|
|
||||||
static void init(const T &, type_record *) {}
|
|
||||||
static void precall(function_call &) {}
|
|
||||||
static void postcall(function_call &, handle) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute specifying the function's name
|
|
||||||
template <>
|
|
||||||
struct process_attribute<name> : process_attribute_default<name> {
|
|
||||||
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute specifying the function's docstring
|
|
||||||
template <>
|
|
||||||
struct process_attribute<doc> : process_attribute_default<doc> {
|
|
||||||
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
|
||||||
template <>
|
|
||||||
struct process_attribute<const char *> : process_attribute_default<const char *> {
|
|
||||||
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
|
||||||
static void init(const char *d, type_record *r) { r->doc = d; }
|
|
||||||
};
|
|
||||||
template <>
|
|
||||||
struct process_attribute<char *> : process_attribute<const char *> {};
|
|
||||||
|
|
||||||
/// Process an attribute indicating the function's return value policy
|
|
||||||
template <>
|
|
||||||
struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
|
||||||
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute which indicates that this is an overloaded function associated with a
|
|
||||||
/// given sibling
|
|
||||||
template <>
|
|
||||||
struct process_attribute<sibling> : process_attribute_default<sibling> {
|
|
||||||
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute which indicates that this function is a method
|
|
||||||
template <>
|
|
||||||
struct process_attribute<is_method> : process_attribute_default<is_method> {
|
|
||||||
static void init(const is_method &s, function_record *r) {
|
|
||||||
r->is_method = true;
|
|
||||||
r->scope = s.class_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute which indicates that this function is a setter
|
|
||||||
template <>
|
|
||||||
struct process_attribute<is_setter> : process_attribute_default<is_setter> {
|
|
||||||
static void init(const is_setter &, function_record *r) { r->is_setter = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute which indicates the parent scope of a method
|
|
||||||
template <>
|
|
||||||
struct process_attribute<scope> : process_attribute_default<scope> {
|
|
||||||
static void init(const scope &s, function_record *r) { r->scope = s.value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an attribute which indicates that this function is an operator
|
|
||||||
template <>
|
|
||||||
struct process_attribute<is_operator> : process_attribute_default<is_operator> {
|
|
||||||
static void init(const is_operator &, function_record *r) { r->is_operator = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<is_new_style_constructor>
|
|
||||||
: process_attribute_default<is_new_style_constructor> {
|
|
||||||
static void init(const is_new_style_constructor &, function_record *r) {
|
|
||||||
r->is_new_style_constructor = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void check_kw_only_arg(const arg &a, function_record *r) {
|
|
||||||
if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) {
|
|
||||||
pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or "
|
|
||||||
"args() argument");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void append_self_arg_if_needed(function_record *r) {
|
|
||||||
if (r->is_method && r->args.empty()) {
|
|
||||||
r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process a keyword argument attribute (*without* a default value)
|
|
||||||
template <>
|
|
||||||
struct process_attribute<arg> : process_attribute_default<arg> {
|
|
||||||
static void init(const arg &a, function_record *r) {
|
|
||||||
append_self_arg_if_needed(r);
|
|
||||||
r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);
|
|
||||||
|
|
||||||
check_kw_only_arg(a, r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a keyword argument attribute (*with* a default value)
|
|
||||||
template <>
|
|
||||||
struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|
||||||
static void init(const arg_v &a, function_record *r) {
|
|
||||||
if (r->is_method && r->args.empty()) {
|
|
||||||
r->args.emplace_back(
|
|
||||||
"self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!a.value) {
|
|
||||||
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
||||||
std::string descr("'");
|
|
||||||
if (a.name) {
|
|
||||||
descr += std::string(a.name) + ": ";
|
|
||||||
}
|
|
||||||
descr += a.type + "'";
|
|
||||||
if (r->is_method) {
|
|
||||||
if (r->name) {
|
|
||||||
descr += " in method '" + (std::string) str(r->scope) + "."
|
|
||||||
+ (std::string) r->name + "'";
|
|
||||||
} else {
|
|
||||||
descr += " in method of '" + (std::string) str(r->scope) + "'";
|
|
||||||
}
|
|
||||||
} else if (r->name) {
|
|
||||||
descr += " in function '" + (std::string) r->name + "'";
|
|
||||||
}
|
|
||||||
pybind11_fail("arg(): could not convert default argument " + descr
|
|
||||||
+ " into a Python object (type not registered yet?)");
|
|
||||||
#else
|
|
||||||
pybind11_fail("arg(): could not convert default argument "
|
|
||||||
"into a Python object (type not registered yet?). "
|
|
||||||
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
|
|
||||||
"more information.");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);
|
|
||||||
|
|
||||||
check_kw_only_arg(a, r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a keyword-only-arguments-follow pseudo argument
|
|
||||||
template <>
|
|
||||||
struct process_attribute<kw_only> : process_attribute_default<kw_only> {
|
|
||||||
static void init(const kw_only &, function_record *r) {
|
|
||||||
append_self_arg_if_needed(r);
|
|
||||||
if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {
|
|
||||||
pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative "
|
|
||||||
"argument location (or omit kw_only() entirely)");
|
|
||||||
}
|
|
||||||
r->nargs_pos = static_cast<std::uint16_t>(r->args.size());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a positional-only-argument maker
|
|
||||||
template <>
|
|
||||||
struct process_attribute<pos_only> : process_attribute_default<pos_only> {
|
|
||||||
static void init(const pos_only &, function_record *r) {
|
|
||||||
append_self_arg_if_needed(r);
|
|
||||||
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
|
|
||||||
if (r->nargs_pos_only > r->nargs_pos) {
|
|
||||||
pybind11_fail("pos_only(): cannot follow a py::args() argument");
|
|
||||||
}
|
|
||||||
// It also can't follow a kw_only, but a static_assert in pybind11.h checks that
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees
|
|
||||||
/// that)
|
|
||||||
template <typename T>
|
|
||||||
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>>
|
|
||||||
: process_attribute_default<handle> {
|
|
||||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a parent class attribute (deprecated, does not support multiple inheritance)
|
|
||||||
template <typename T>
|
|
||||||
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
|
||||||
static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a multiple inheritance attribute
|
|
||||||
template <>
|
|
||||||
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
|
||||||
static void init(const multiple_inheritance &, type_record *r) {
|
|
||||||
r->multiple_inheritance = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {
|
|
||||||
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<custom_type_setup> {
|
|
||||||
static void init(const custom_type_setup &value, type_record *r) {
|
|
||||||
r->custom_type_setup_callback = value.value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<is_final> : process_attribute_default<is_final> {
|
|
||||||
static void init(const is_final &, type_record *r) { r->is_final = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
|
|
||||||
static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<metaclass> : process_attribute_default<metaclass> {
|
|
||||||
static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct process_attribute<module_local> : process_attribute_default<module_local> {
|
|
||||||
static void init(const module_local &l, type_record *r) { r->module_local = l.value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process a 'prepend' attribute, putting this at the beginning of the overload chain
|
|
||||||
template <>
|
|
||||||
struct process_attribute<prepend> : process_attribute_default<prepend> {
|
|
||||||
static void init(const prepend &, function_record *r) { r->prepend = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Process an 'arithmetic' attribute for enums (does nothing here)
|
|
||||||
template <>
|
|
||||||
struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
|
||||||
struct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
|
||||||
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
|
|
||||||
* otherwise
|
|
||||||
*/
|
|
||||||
template <size_t Nurse, size_t Patient>
|
|
||||||
struct process_attribute<keep_alive<Nurse, Patient>>
|
|
||||||
: public process_attribute_default<keep_alive<Nurse, Patient>> {
|
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
|
||||||
static void precall(function_call &call) {
|
|
||||||
keep_alive_impl(Nurse, Patient, call, handle());
|
|
||||||
}
|
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
|
||||||
static void postcall(function_call &, handle) {}
|
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
|
||||||
static void precall(function_call &) {}
|
|
||||||
template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
|
||||||
static void postcall(function_call &call, handle ret) {
|
|
||||||
keep_alive_impl(Nurse, Patient, call, ret);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Recursively iterate over variadic template arguments
|
|
||||||
template <typename... Args>
|
|
||||||
struct process_attributes {
|
|
||||||
static void init(const Args &...args, function_record *r) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
|
|
||||||
using expander = int[];
|
|
||||||
(void) expander{
|
|
||||||
0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
|
|
||||||
}
|
|
||||||
static void init(const Args &...args, type_record *r) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
|
|
||||||
using expander = int[];
|
|
||||||
(void) expander{0,
|
|
||||||
(process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
|
|
||||||
}
|
|
||||||
static void precall(function_call &call) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call);
|
|
||||||
using expander = int[];
|
|
||||||
(void) expander{0,
|
|
||||||
(process_attribute<typename std::decay<Args>::type>::precall(call), 0)...};
|
|
||||||
}
|
|
||||||
static void postcall(function_call &call, handle fn_ret) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret);
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret);
|
|
||||||
using expander = int[];
|
|
||||||
(void) expander{
|
|
||||||
0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0)...};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using is_call_guard = is_instantiation<call_guard, T>;
|
|
||||||
|
|
||||||
/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)
|
|
||||||
template <typename... Extra>
|
|
||||||
using extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;
|
|
||||||
|
|
||||||
/// Check the number of named arguments at compile time
|
|
||||||
template <typename... Extra,
|
|
||||||
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
|
|
||||||
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
|
|
||||||
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs);
|
|
||||||
return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
208
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
208
3rdparty/pybind11/include/pybind11/buffer_info.h
vendored
@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/buffer_info.h: Python buffer object interface
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// Default, C-style strides
|
|
||||||
inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
|
||||||
auto ndim = shape.size();
|
|
||||||
std::vector<ssize_t> strides(ndim, itemsize);
|
|
||||||
if (ndim > 0) {
|
|
||||||
for (size_t i = ndim - 1; i > 0; --i) {
|
|
||||||
strides[i - 1] = strides[i] * shape[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strides;
|
|
||||||
}
|
|
||||||
|
|
||||||
// F-style strides; default when constructing an array_t with `ExtraFlags & f_style`
|
|
||||||
inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
|
|
||||||
auto ndim = shape.size();
|
|
||||||
std::vector<ssize_t> strides(ndim, itemsize);
|
|
||||||
for (size_t i = 1; i < ndim; ++i) {
|
|
||||||
strides[i] = strides[i - 1] * shape[i - 1];
|
|
||||||
}
|
|
||||||
return strides;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename SFINAE = void>
|
|
||||||
struct compare_buffer_info;
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/// Information record describing a Python buffer object
|
|
||||||
struct buffer_info {
|
|
||||||
void *ptr = nullptr; // Pointer to the underlying storage
|
|
||||||
ssize_t itemsize = 0; // Size of individual items in bytes
|
|
||||||
ssize_t size = 0; // Total number of entries
|
|
||||||
std::string format; // For homogeneous buffers, this should be set to
|
|
||||||
// format_descriptor<T>::format()
|
|
||||||
ssize_t ndim = 0; // Number of dimensions
|
|
||||||
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
|
||||||
std::vector<ssize_t> strides; // Number of bytes between adjacent entries
|
|
||||||
// (for each per dimension)
|
|
||||||
bool readonly = false; // flag to indicate if the underlying storage may be written to
|
|
||||||
|
|
||||||
buffer_info() = default;
|
|
||||||
|
|
||||||
buffer_info(void *ptr,
|
|
||||||
ssize_t itemsize,
|
|
||||||
const std::string &format,
|
|
||||||
ssize_t ndim,
|
|
||||||
detail::any_container<ssize_t> shape_in,
|
|
||||||
detail::any_container<ssize_t> strides_in,
|
|
||||||
bool readonly = false)
|
|
||||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
|
||||||
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
|
|
||||||
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
|
|
||||||
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < (size_t) ndim; ++i) {
|
|
||||||
size *= shape[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
buffer_info(T *ptr,
|
|
||||||
detail::any_container<ssize_t> shape_in,
|
|
||||||
detail::any_container<ssize_t> strides_in,
|
|
||||||
bool readonly = false)
|
|
||||||
: buffer_info(private_ctr_tag(),
|
|
||||||
ptr,
|
|
||||||
sizeof(T),
|
|
||||||
format_descriptor<T>::format(),
|
|
||||||
static_cast<ssize_t>(shape_in->size()),
|
|
||||||
std::move(shape_in),
|
|
||||||
std::move(strides_in),
|
|
||||||
readonly) {}
|
|
||||||
|
|
||||||
buffer_info(void *ptr,
|
|
||||||
ssize_t itemsize,
|
|
||||||
const std::string &format,
|
|
||||||
ssize_t size,
|
|
||||||
bool readonly = false)
|
|
||||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
buffer_info(T *ptr, ssize_t size, bool readonly = false)
|
|
||||||
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
buffer_info(const T *ptr, ssize_t size, bool readonly = true)
|
|
||||||
: buffer_info(
|
|
||||||
const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}
|
|
||||||
|
|
||||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
|
||||||
: buffer_info(
|
|
||||||
view->buf,
|
|
||||||
view->itemsize,
|
|
||||||
view->format,
|
|
||||||
view->ndim,
|
|
||||||
{view->shape, view->shape + view->ndim},
|
|
||||||
/* Though buffer::request() requests PyBUF_STRIDES, ctypes objects
|
|
||||||
* ignore this flag and return a view with NULL strides.
|
|
||||||
* When strides are NULL, build them manually. */
|
|
||||||
view->strides
|
|
||||||
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
|
|
||||||
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
|
|
||||||
(view->readonly != 0)) {
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
|
||||||
this->m_view = view;
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
|
||||||
this->ownview = ownview;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_info(const buffer_info &) = delete;
|
|
||||||
buffer_info &operator=(const buffer_info &) = delete;
|
|
||||||
|
|
||||||
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
|
|
||||||
|
|
||||||
buffer_info &operator=(buffer_info &&rhs) noexcept {
|
|
||||||
ptr = rhs.ptr;
|
|
||||||
itemsize = rhs.itemsize;
|
|
||||||
size = rhs.size;
|
|
||||||
format = std::move(rhs.format);
|
|
||||||
ndim = rhs.ndim;
|
|
||||||
shape = std::move(rhs.shape);
|
|
||||||
strides = std::move(rhs.strides);
|
|
||||||
std::swap(m_view, rhs.m_view);
|
|
||||||
std::swap(ownview, rhs.ownview);
|
|
||||||
readonly = rhs.readonly;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~buffer_info() {
|
|
||||||
if (m_view && ownview) {
|
|
||||||
PyBuffer_Release(m_view);
|
|
||||||
delete m_view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_buffer *view() const { return m_view; }
|
|
||||||
Py_buffer *&view() { return m_view; }
|
|
||||||
|
|
||||||
/* True if the buffer item type is equivalent to `T`. */
|
|
||||||
// To define "equivalent" by example:
|
|
||||||
// `buffer_info::item_type_is_equivalent_to<int>(b)` and
|
|
||||||
// `buffer_info::item_type_is_equivalent_to<long>(b)` may both be true
|
|
||||||
// on some platforms, but `int` and `unsigned` will never be equivalent.
|
|
||||||
// For the ground truth, please inspect `detail::compare_buffer_info<>`.
|
|
||||||
template <typename T>
|
|
||||||
bool item_type_is_equivalent_to() const {
|
|
||||||
return detail::compare_buffer_info<T>::compare(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct private_ctr_tag {};
|
|
||||||
|
|
||||||
buffer_info(private_ctr_tag,
|
|
||||||
void *ptr,
|
|
||||||
ssize_t itemsize,
|
|
||||||
const std::string &format,
|
|
||||||
ssize_t ndim,
|
|
||||||
detail::any_container<ssize_t> &&shape_in,
|
|
||||||
detail::any_container<ssize_t> &&strides_in,
|
|
||||||
bool readonly)
|
|
||||||
: buffer_info(
|
|
||||||
ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}
|
|
||||||
|
|
||||||
Py_buffer *m_view = nullptr;
|
|
||||||
bool ownview = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <typename T, typename SFINAE>
|
|
||||||
struct compare_buffer_info {
|
|
||||||
static bool compare(const buffer_info &b) {
|
|
||||||
// NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *`
|
|
||||||
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
|
||||||
static bool compare(const buffer_info &b) {
|
|
||||||
return (size_t) b.itemsize == sizeof(T)
|
|
||||||
&& (b.format == format_descriptor<T>::value
|
|
||||||
|| ((sizeof(T) == sizeof(long))
|
|
||||||
&& b.format == (std::is_unsigned<T>::value ? "L" : "l"))
|
|
||||||
|| ((sizeof(T) == sizeof(size_t))
|
|
||||||
&& b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
1704
3rdparty/pybind11/include/pybind11/cast.h
vendored
1704
3rdparty/pybind11/include/pybind11/cast.h
vendored
File diff suppressed because it is too large
Load Diff
225
3rdparty/pybind11/include/pybind11/chrono.h
vendored
225
3rdparty/pybind11/include/pybind11/chrono.h
vendored
@ -1,225 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
|
|
||||||
|
|
||||||
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
|
||||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <cmath>
|
|
||||||
#include <ctime>
|
|
||||||
#include <datetime.h>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <typename type>
|
|
||||||
class duration_caster {
|
|
||||||
public:
|
|
||||||
using rep = typename type::rep;
|
|
||||||
using period = typename type::period;
|
|
||||||
|
|
||||||
// signed 25 bits required by the standard.
|
|
||||||
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;
|
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
|
||||||
if (!PyDateTimeAPI) {
|
|
||||||
PyDateTime_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!src) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// If invoked with datetime.delta object
|
|
||||||
if (PyDelta_Check(src.ptr())) {
|
|
||||||
value = type(duration_cast<duration<rep, period>>(
|
|
||||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
|
|
||||||
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
|
|
||||||
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If invoked with a float we assume it is seconds and convert
|
|
||||||
if (PyFloat_Check(src.ptr())) {
|
|
||||||
value = type(duration_cast<duration<rep, period>>(
|
|
||||||
duration<double>(PyFloat_AsDouble(src.ptr()))));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a duration just return it back
|
|
||||||
static const std::chrono::duration<rep, period> &
|
|
||||||
get_duration(const std::chrono::duration<rep, period> &src) {
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a time_point get the time_since_epoch
|
|
||||||
template <typename Clock>
|
|
||||||
static std::chrono::duration<rep, period>
|
|
||||||
get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
|
||||||
return src.time_since_epoch();
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
// Use overloaded function to get our duration from our source
|
|
||||||
// Works out if it is a duration or time_point and get the duration
|
|
||||||
auto d = get_duration(src);
|
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
|
||||||
if (!PyDateTimeAPI) {
|
|
||||||
PyDateTime_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare these special duration types so the conversions happen with the correct
|
|
||||||
// primitive types (int)
|
|
||||||
using dd_t = duration<int, std::ratio<86400>>;
|
|
||||||
using ss_t = duration<int, std::ratio<1>>;
|
|
||||||
using us_t = duration<int, std::micro>;
|
|
||||||
|
|
||||||
auto dd = duration_cast<dd_t>(d);
|
|
||||||
auto subd = d - dd;
|
|
||||||
auto ss = duration_cast<ss_t>(subd);
|
|
||||||
auto us = duration_cast<us_t>(subd - ss);
|
|
||||||
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, const_name("datetime.timedelta"));
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
|
|
||||||
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER)
|
|
||||||
if (localtime_s(buf, time))
|
|
||||||
return nullptr;
|
|
||||||
return buf;
|
|
||||||
#else
|
|
||||||
static std::mutex mtx;
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
|
||||||
std::tm *tm_ptr = std::localtime(time);
|
|
||||||
if (tm_ptr != nullptr) {
|
|
||||||
*buf = *tm_ptr;
|
|
||||||
}
|
|
||||||
return tm_ptr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is for casting times on the system clock into datetime.datetime instances
|
|
||||||
template <typename Duration>
|
|
||||||
class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
|
||||||
public:
|
|
||||||
using type = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
|
||||||
bool load(handle src, bool) {
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
|
||||||
if (!PyDateTimeAPI) {
|
|
||||||
PyDateTime_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!src) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tm cal;
|
|
||||||
microseconds msecs;
|
|
||||||
|
|
||||||
if (PyDateTime_Check(src.ptr())) {
|
|
||||||
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
|
|
||||||
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
|
|
||||||
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
|
|
||||||
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
|
||||||
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
|
||||||
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
|
||||||
cal.tm_isdst = -1;
|
|
||||||
msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
|
|
||||||
} else if (PyDate_Check(src.ptr())) {
|
|
||||||
cal.tm_sec = 0;
|
|
||||||
cal.tm_min = 0;
|
|
||||||
cal.tm_hour = 0;
|
|
||||||
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
|
||||||
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
|
||||||
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
|
||||||
cal.tm_isdst = -1;
|
|
||||||
msecs = microseconds(0);
|
|
||||||
} else if (PyTime_Check(src.ptr())) {
|
|
||||||
cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr());
|
|
||||||
cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr());
|
|
||||||
cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr());
|
|
||||||
cal.tm_mday = 1; // This date (day, month, year) = (1, 0, 70)
|
|
||||||
cal.tm_mon = 0; // represents 1-Jan-1970, which is the first
|
|
||||||
cal.tm_year = 70; // earliest available date for Python's datetime
|
|
||||||
cal.tm_isdst = -1;
|
|
||||||
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,
|
|
||||||
return_value_policy /* policy */,
|
|
||||||
handle /* parent */) {
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
// Lazy initialise the PyDateTime import
|
|
||||||
if (!PyDateTimeAPI) {
|
|
||||||
PyDateTime_IMPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get out microseconds, and make sure they are positive, to avoid bug in eastern
|
|
||||||
// hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)
|
|
||||||
using us_t = duration<int, std::micro>;
|
|
||||||
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
|
|
||||||
if (us.count() < 0) {
|
|
||||||
us += seconds(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
|
|
||||||
// > If std::time_t has lower precision, it is implementation-defined whether the value is
|
|
||||||
// rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
|
|
||||||
std::time_t tt
|
|
||||||
= system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
|
|
||||||
|
|
||||||
std::tm localtime;
|
|
||||||
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
|
|
||||||
if (!localtime_ptr) {
|
|
||||||
throw cast_error("Unable to represent system_clock in local time");
|
|
||||||
}
|
|
||||||
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
|
||||||
localtime.tm_mon + 1,
|
|
||||||
localtime.tm_mday,
|
|
||||||
localtime.tm_hour,
|
|
||||||
localtime.tm_min,
|
|
||||||
localtime.tm_sec,
|
|
||||||
us.count());
|
|
||||||
}
|
|
||||||
PYBIND11_TYPE_CASTER(type, const_name("datetime.datetime"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
|
||||||
// since they are not measured on calendar time. So instead we just make them timedeltas
|
|
||||||
// Or if they have passed us a time as a float we convert that
|
|
||||||
template <typename Clock, typename Duration>
|
|
||||||
class type_caster<std::chrono::time_point<Clock, Duration>>
|
|
||||||
: public duration_caster<std::chrono::time_point<Clock, Duration>> {};
|
|
||||||
|
|
||||||
template <typename Rep, typename Period>
|
|
||||||
class type_caster<std::chrono::duration<Rep, Period>>
|
|
||||||
: public duration_caster<std::chrono::duration<Rep, Period>> {};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
2
3rdparty/pybind11/include/pybind11/common.h
vendored
2
3rdparty/pybind11/include/pybind11/common.h
vendored
@ -1,2 +0,0 @@
|
|||||||
#include "detail/common.h"
|
|
||||||
#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'."
|
|
74
3rdparty/pybind11/include/pybind11/complex.h
vendored
74
3rdparty/pybind11/include/pybind11/complex.h
vendored
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/complex.h: Complex number support
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
#include <complex>
|
|
||||||
|
|
||||||
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
|
||||||
#ifdef I
|
|
||||||
# undef I
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
|
||||||
static constexpr const char c = format_descriptor<T>::c;
|
|
||||||
static constexpr const char value[3] = {'Z', c, '\0'};
|
|
||||||
static std::string format() { return std::string(value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef PYBIND11_CPP17
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr const char
|
|
||||||
format_descriptor<std::complex<T>,
|
|
||||||
detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
|
||||||
static constexpr bool value = true;
|
|
||||||
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class type_caster<std::complex<T>> {
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!src) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!convert && !PyComplex_Check(src.ptr())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
|
||||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = std::complex<T>((T) result.real, (T) result.imag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle
|
|
||||||
cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
|
||||||
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(std::complex<T>, const_name("complex"));
|
|
||||||
};
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
743
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
743
3rdparty/pybind11/include/pybind11/detail/class.h
vendored
@ -1,743 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/class.h: Python C API implementation details for py::class_
|
|
||||||
|
|
||||||
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../attr.h"
|
|
||||||
#include "../options.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
# define PYBIND11_BUILTIN_QUALNAME
|
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)
|
|
||||||
#else
|
|
||||||
// In PyPy, we still set __qualname__ so that we can produce reliable function type
|
|
||||||
// signatures; in CPython this macro expands to nothing:
|
|
||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) \
|
|
||||||
setattr((PyObject *) obj, "__qualname__", nameobj)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
return type->tp_name;
|
|
||||||
#else
|
|
||||||
auto module_name = handle((PyObject *) type).attr("__module__").cast<std::string>();
|
|
||||||
if (module_name == PYBIND11_BUILTINS_MODULE)
|
|
||||||
return type->tp_name;
|
|
||||||
else
|
|
||||||
return std::move(module_name) + "." + type->tp_name;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyTypeObject *type_incref(PyTypeObject *type) {
|
|
||||||
Py_INCREF(type);
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
|
|
||||||
/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.
|
|
||||||
extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {
|
|
||||||
return PyProperty_Type.tp_descr_get(self, cls, cls);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.
|
|
||||||
extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {
|
|
||||||
PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);
|
|
||||||
return PyProperty_Type.tp_descr_set(self, cls, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward declaration to use in `make_static_property_type()`
|
|
||||||
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type);
|
|
||||||
|
|
||||||
/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
|
|
||||||
methods are modified to always use the object type instead of a concrete instance.
|
|
||||||
Return value: New reference. */
|
|
||||||
inline PyTypeObject *make_static_property_type() {
|
|
||||||
constexpr auto *name = "pybind11_static_property";
|
|
||||||
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
|
||||||
|
|
||||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
|
||||||
issue no Python C API calls which could potentially invoke the
|
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
|
||||||
turn find the newly constructed type in an invalid state) */
|
|
||||||
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
|
||||||
if (!heap_type) {
|
|
||||||
pybind11_fail("make_static_property_type(): error allocating type!");
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
|
||||||
# ifdef PYBIND11_BUILTIN_QUALNAME
|
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
auto *type = &heap_type->ht_type;
|
|
||||||
type->tp_name = name;
|
|
||||||
type->tp_base = type_incref(&PyProperty_Type);
|
|
||||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
|
||||||
type->tp_descr_get = pybind11_static_get;
|
|
||||||
type->tp_descr_set = pybind11_static_set;
|
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
|
||||||
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
|
|
||||||
}
|
|
||||||
|
|
||||||
# if PY_VERSION_HEX >= 0x030C0000
|
|
||||||
// PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE.
|
|
||||||
// Since Python-3.12 property-derived types are required to
|
|
||||||
// have dynamic attributes (to set `__doc__`)
|
|
||||||
enable_dynamic_attributes(heap_type);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // PYPY
|
|
||||||
|
|
||||||
/** PyPy has some issues with the above C API, so we evaluate Python code instead.
|
|
||||||
This function will only be called once so performance isn't really a concern.
|
|
||||||
Return value: New reference. */
|
|
||||||
inline PyTypeObject *make_static_property_type() {
|
|
||||||
auto d = dict();
|
|
||||||
PyObject *result = PyRun_String(R"(\
|
|
||||||
class pybind11_static_property(property):
|
|
||||||
def __get__(self, obj, cls):
|
|
||||||
return property.__get__(self, cls, cls)
|
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
|
||||||
cls = obj if isinstance(obj, type) else type(obj)
|
|
||||||
property.__set__(self, cls, value)
|
|
||||||
)",
|
|
||||||
Py_file_input,
|
|
||||||
d.ptr(),
|
|
||||||
d.ptr());
|
|
||||||
if (result == nullptr)
|
|
||||||
throw error_already_set();
|
|
||||||
Py_DECREF(result);
|
|
||||||
return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // PYPY
|
|
||||||
|
|
||||||
/** Types with static properties need to handle `Type.static_prop = x` in a specific way.
|
|
||||||
By default, Python replaces the `static_property` itself, but for wrapped C++ types
|
|
||||||
we need to call `static_property.__set__()` in order to propagate the new value to
|
|
||||||
the underlying C++ data structure. */
|
|
||||||
extern "C" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {
|
|
||||||
// Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
|
|
||||||
// descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
|
|
||||||
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
|
||||||
|
|
||||||
// The following assignment combinations are possible:
|
|
||||||
// 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)`
|
|
||||||
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
|
|
||||||
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
|
|
||||||
auto *const static_prop = (PyObject *) get_internals().static_property_type;
|
|
||||||
const auto call_descr_set = (descr != nullptr) && (value != nullptr)
|
|
||||||
&& (PyObject_IsInstance(descr, static_prop) != 0)
|
|
||||||
&& (PyObject_IsInstance(value, static_prop) == 0);
|
|
||||||
if (call_descr_set) {
|
|
||||||
// Call `static_property.__set__()` instead of replacing the `static_property`.
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
|
|
||||||
#else
|
|
||||||
if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
// Replace existing attribute.
|
|
||||||
return PyType_Type.tp_setattro(obj, name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing
|
|
||||||
* methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function,
|
|
||||||
* when called on a class, or a PyMethod, when called on an instance. Override that behaviour here
|
|
||||||
* to do a special case bypass for PyInstanceMethod_Types.
|
|
||||||
*/
|
|
||||||
extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) {
|
|
||||||
PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
|
|
||||||
if (descr && PyInstanceMethod_Check(descr)) {
|
|
||||||
Py_INCREF(descr);
|
|
||||||
return descr;
|
|
||||||
}
|
|
||||||
return PyType_Type.tp_getattro(obj, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// metaclass `__call__` function that is used to create all pybind11 objects.
|
|
||||||
extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {
|
|
||||||
|
|
||||||
// use the default metaclass call to create/initialize the object
|
|
||||||
PyObject *self = PyType_Type.tp_call(type, args, kwargs);
|
|
||||||
if (self == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This must be a pybind11 instance
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
|
||||||
|
|
||||||
// Ensure that the base __init__ function(s) were called
|
|
||||||
for (const auto &vh : values_and_holders(instance)) {
|
|
||||||
if (!vh.holder_constructed()) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%.200s.__init__() must be called when overriding __init__",
|
|
||||||
get_fully_qualified_tp_name(vh.type->type).c_str());
|
|
||||||
Py_DECREF(self);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cleanup the type-info for a pybind11-registered type.
|
|
||||||
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
|
|
||||||
auto *type = (PyTypeObject *) obj;
|
|
||||||
auto &internals = get_internals();
|
|
||||||
|
|
||||||
// A pybind11-registered type will:
|
|
||||||
// 1) be found in internals.registered_types_py
|
|
||||||
// 2) have exactly one associated `detail::type_info`
|
|
||||||
auto found_type = internals.registered_types_py.find(type);
|
|
||||||
if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1
|
|
||||||
&& found_type->second[0]->type == type) {
|
|
||||||
|
|
||||||
auto *tinfo = found_type->second[0];
|
|
||||||
auto tindex = std::type_index(*tinfo->cpptype);
|
|
||||||
internals.direct_conversions.erase(tindex);
|
|
||||||
|
|
||||||
if (tinfo->module_local) {
|
|
||||||
get_local_internals().registered_types_cpp.erase(tindex);
|
|
||||||
} else {
|
|
||||||
internals.registered_types_cpp.erase(tindex);
|
|
||||||
}
|
|
||||||
internals.registered_types_py.erase(tinfo->type);
|
|
||||||
|
|
||||||
// Actually just `std::erase_if`, but that's only available in C++20
|
|
||||||
auto &cache = internals.inactive_override_cache;
|
|
||||||
for (auto it = cache.begin(), last = cache.end(); it != last;) {
|
|
||||||
if (it->first == (PyObject *) tinfo->type) {
|
|
||||||
it = cache.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete tinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyType_Type.tp_dealloc(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** This metaclass is assigned by default to all pybind11 types and is required in order
|
|
||||||
for static properties to function correctly. Users may override this using `py::metaclass`.
|
|
||||||
Return value: New reference. */
|
|
||||||
inline PyTypeObject *make_default_metaclass() {
|
|
||||||
constexpr auto *name = "pybind11_type";
|
|
||||||
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
|
||||||
|
|
||||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
|
||||||
issue no Python C API calls which could potentially invoke the
|
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
|
||||||
turn find the newly constructed type in an invalid state) */
|
|
||||||
auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
|
|
||||||
if (!heap_type) {
|
|
||||||
pybind11_fail("make_default_metaclass(): error allocating metaclass!");
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto *type = &heap_type->ht_type;
|
|
||||||
type->tp_name = name;
|
|
||||||
type->tp_base = type_incref(&PyType_Type);
|
|
||||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
|
||||||
|
|
||||||
type->tp_call = pybind11_meta_call;
|
|
||||||
|
|
||||||
type->tp_setattro = pybind11_meta_setattro;
|
|
||||||
type->tp_getattro = pybind11_meta_getattro;
|
|
||||||
|
|
||||||
type->tp_dealloc = pybind11_meta_dealloc;
|
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
|
||||||
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
|
|
||||||
}
|
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For multiple inheritance types we need to recursively register/deregister base pointers for any
|
|
||||||
/// base classes with pointers that are difference from the instance value pointer so that we can
|
|
||||||
/// correctly recognize an offset base class pointer. This calls a function with any offset base
|
|
||||||
/// ptrs.
|
|
||||||
inline void traverse_offset_bases(void *valueptr,
|
|
||||||
const detail::type_info *tinfo,
|
|
||||||
instance *self,
|
|
||||||
bool (*f)(void * /*parentptr*/, instance * /*self*/)) {
|
|
||||||
for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {
|
|
||||||
if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {
|
|
||||||
for (auto &c : parent_tinfo->implicit_casts) {
|
|
||||||
if (c.first == tinfo->cpptype) {
|
|
||||||
auto *parentptr = c.second(valueptr);
|
|
||||||
if (parentptr != valueptr) {
|
|
||||||
f(parentptr, self);
|
|
||||||
}
|
|
||||||
traverse_offset_bases(parentptr, parent_tinfo, self, f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool register_instance_impl(void *ptr, instance *self) {
|
|
||||||
get_internals().registered_instances.emplace(ptr, self);
|
|
||||||
return true; // unused, but gives the same signature as the deregister func
|
|
||||||
}
|
|
||||||
inline bool deregister_instance_impl(void *ptr, instance *self) {
|
|
||||||
auto ®istered_instances = get_internals().registered_instances;
|
|
||||||
auto range = registered_instances.equal_range(ptr);
|
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
|
||||||
if (self == it->second) {
|
|
||||||
registered_instances.erase(it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
|
|
||||||
register_instance_impl(valptr, self);
|
|
||||||
if (!tinfo->simple_ancestors) {
|
|
||||||
traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
|
|
||||||
bool ret = deregister_instance_impl(valptr, self);
|
|
||||||
if (!tinfo->simple_ancestors) {
|
|
||||||
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Instance creation function for all pybind11 types. It allocates the internal instance layout
|
|
||||||
/// for holding C++ objects and holders. Allocation is done lazily (the first time the instance is
|
|
||||||
/// cast to a reference or pointer), and initialization is done by an `__init__` function.
|
|
||||||
inline PyObject *make_new_instance(PyTypeObject *type) {
|
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first
|
|
||||||
// inherited object is a plain Python type (i.e. not derived from an extension type). Fix it.
|
|
||||||
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
|
|
||||||
if (type->tp_basicsize < instance_size) {
|
|
||||||
type->tp_basicsize = instance_size;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
PyObject *self = type->tp_alloc(type, 0);
|
|
||||||
auto *inst = reinterpret_cast<instance *>(self);
|
|
||||||
// Allocate the value/holder internals:
|
|
||||||
inst->allocate_layout();
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Instance creation function for all pybind11 types. It only allocates space for the
|
|
||||||
/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.
|
|
||||||
extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {
|
|
||||||
return make_new_instance(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An `__init__` function constructs the C++ object. Users should provide at least one
|
|
||||||
/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
|
|
||||||
/// following default function will be used which simply throws an exception.
|
|
||||||
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
|
||||||
PyTypeObject *type = Py_TYPE(self);
|
|
||||||
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void add_patient(PyObject *nurse, PyObject *patient) {
|
|
||||||
auto &internals = get_internals();
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(nurse);
|
|
||||||
instance->has_patients = true;
|
|
||||||
Py_INCREF(patient);
|
|
||||||
internals.patients[nurse].push_back(patient);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear_patients(PyObject *self) {
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
|
||||||
auto &internals = get_internals();
|
|
||||||
auto pos = internals.patients.find(self);
|
|
||||||
assert(pos != internals.patients.end());
|
|
||||||
// Clearing the patients can cause more Python code to run, which
|
|
||||||
// can invalidate the iterator. Extract the vector of patients
|
|
||||||
// from the unordered_map first.
|
|
||||||
auto patients = std::move(pos->second);
|
|
||||||
internals.patients.erase(pos);
|
|
||||||
instance->has_patients = false;
|
|
||||||
for (PyObject *&patient : patients) {
|
|
||||||
Py_CLEAR(patient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears all internal data from the instance and removes it from registered instances in
|
|
||||||
/// preparation for deallocation.
|
|
||||||
inline void clear_instance(PyObject *self) {
|
|
||||||
auto *instance = reinterpret_cast<detail::instance *>(self);
|
|
||||||
|
|
||||||
// Deallocate any values/holders, if present:
|
|
||||||
for (auto &v_h : values_and_holders(instance)) {
|
|
||||||
if (v_h) {
|
|
||||||
|
|
||||||
// We have to deregister before we call dealloc because, for virtual MI types, we still
|
|
||||||
// need to be able to get the parent pointers.
|
|
||||||
if (v_h.instance_registered()
|
|
||||||
&& !deregister_instance(instance, v_h.value_ptr(), v_h.type)) {
|
|
||||||
pybind11_fail(
|
|
||||||
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance->owned || v_h.holder_constructed()) {
|
|
||||||
v_h.type->dealloc(v_h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Deallocate the value/holder layout internals:
|
|
||||||
instance->deallocate_layout();
|
|
||||||
|
|
||||||
if (instance->weakrefs) {
|
|
||||||
PyObject_ClearWeakRefs(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject **dict_ptr = _PyObject_GetDictPtr(self);
|
|
||||||
if (dict_ptr) {
|
|
||||||
Py_CLEAR(*dict_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance->has_patients) {
|
|
||||||
clear_patients(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
|
|
||||||
/// to destroy the C++ object itself, while the rest is Python bookkeeping.
|
|
||||||
extern "C" inline void pybind11_object_dealloc(PyObject *self) {
|
|
||||||
auto *type = Py_TYPE(self);
|
|
||||||
|
|
||||||
// If this is a GC tracked object, untrack it first
|
|
||||||
// Note that the track call is implicitly done by the
|
|
||||||
// default tp_alloc, which we never override.
|
|
||||||
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) != 0) {
|
|
||||||
PyObject_GC_UnTrack(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_instance(self);
|
|
||||||
|
|
||||||
type->tp_free(self);
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x03080000
|
|
||||||
// `type->tp_dealloc != pybind11_object_dealloc` means that we're being called
|
|
||||||
// as part of a derived type's dealloc, in which case we're not allowed to decref
|
|
||||||
// the type here. For cross-module compatibility, we shouldn't compare directly
|
|
||||||
// with `pybind11_object_dealloc`, but with the common one stashed in internals.
|
|
||||||
auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base;
|
|
||||||
if (type->tp_dealloc == pybind11_object_type->tp_dealloc)
|
|
||||||
Py_DECREF(type);
|
|
||||||
#else
|
|
||||||
// This was not needed before Python 3.8 (Python issue 35810)
|
|
||||||
// https://github.com/pybind/pybind11/issues/1946
|
|
||||||
Py_DECREF(type);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string error_string();
|
|
||||||
|
|
||||||
/** Create the type which can be used as a common base for all classes. This is
|
|
||||||
needed in order to satisfy Python's requirements for multiple inheritance.
|
|
||||||
Return value: New reference. */
|
|
||||||
inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
|
|
||||||
constexpr auto *name = "pybind11_object";
|
|
||||||
auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
|
|
||||||
|
|
||||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
|
||||||
issue no Python C API calls which could potentially invoke the
|
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
|
||||||
turn find the newly constructed type in an invalid state) */
|
|
||||||
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
|
||||||
if (!heap_type) {
|
|
||||||
pybind11_fail("make_object_base_type(): error allocating type!");
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_type->ht_name = name_obj.inc_ref().ptr();
|
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
|
||||||
heap_type->ht_qualname = name_obj.inc_ref().ptr();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto *type = &heap_type->ht_type;
|
|
||||||
type->tp_name = name;
|
|
||||||
type->tp_base = type_incref(&PyBaseObject_Type);
|
|
||||||
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
|
||||||
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
|
|
||||||
|
|
||||||
type->tp_new = pybind11_object_new;
|
|
||||||
type->tp_init = pybind11_object_init;
|
|
||||||
type->tp_dealloc = pybind11_object_dealloc;
|
|
||||||
|
|
||||||
/* Support weak references (needed for the keep_alive feature) */
|
|
||||||
type->tp_weaklistoffset = offsetof(instance, weakrefs);
|
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
|
||||||
pybind11_fail("PyType_Ready failed in make_object_base_type(): " + error_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
|
|
||||||
|
|
||||||
assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
|
||||||
return (PyObject *) heap_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
|
|
||||||
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
|
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
|
||||||
Py_VISIT(dict);
|
|
||||||
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
|
|
||||||
#if PY_VERSION_HEX >= 0x03090000
|
|
||||||
Py_VISIT(Py_TYPE(self));
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dynamic_attr: Allow the GC to clear the dictionary.
|
|
||||||
extern "C" inline int pybind11_clear(PyObject *self) {
|
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
|
||||||
Py_CLEAR(dict);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Give instances of this type a `__dict__` and opt into garbage collection.
|
|
||||||
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
|
||||||
auto *type = &heap_type->ht_type;
|
|
||||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
|
||||||
#if PY_VERSION_HEX < 0x030B0000
|
|
||||||
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
|
||||||
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
|
|
||||||
#else
|
|
||||||
type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;
|
|
||||||
#endif
|
|
||||||
type->tp_traverse = pybind11_traverse;
|
|
||||||
type->tp_clear = pybind11_clear;
|
|
||||||
|
|
||||||
static PyGetSetDef getset[] = {{
|
|
||||||
#if PY_VERSION_HEX < 0x03070000
|
|
||||||
const_cast<char *>("__dict__"),
|
|
||||||
#else
|
|
||||||
"__dict__",
|
|
||||||
#endif
|
|
||||||
PyObject_GenericGetDict,
|
|
||||||
PyObject_GenericSetDict,
|
|
||||||
nullptr,
|
|
||||||
nullptr},
|
|
||||||
{nullptr, nullptr, nullptr, nullptr, nullptr}};
|
|
||||||
type->tp_getset = getset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// buffer_protocol: Fill in the view as specified by flags.
|
|
||||||
extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {
|
|
||||||
// Look for a `get_buffer` implementation in this type's info or any bases (following MRO).
|
|
||||||
type_info *tinfo = nullptr;
|
|
||||||
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
|
|
||||||
tinfo = get_type_info((PyTypeObject *) type.ptr());
|
|
||||||
if (tinfo && tinfo->get_buffer) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (view == nullptr || !tinfo || !tinfo->get_buffer) {
|
|
||||||
if (view) {
|
|
||||||
view->obj = nullptr;
|
|
||||||
}
|
|
||||||
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
std::memset(view, 0, sizeof(Py_buffer));
|
|
||||||
buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
|
|
||||||
if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {
|
|
||||||
delete info;
|
|
||||||
// view->obj = nullptr; // Was just memset to 0, so not necessary
|
|
||||||
PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
view->obj = obj;
|
|
||||||
view->ndim = 1;
|
|
||||||
view->internal = info;
|
|
||||||
view->buf = info->ptr;
|
|
||||||
view->itemsize = info->itemsize;
|
|
||||||
view->len = view->itemsize;
|
|
||||||
for (auto s : info->shape) {
|
|
||||||
view->len *= s;
|
|
||||||
}
|
|
||||||
view->readonly = static_cast<int>(info->readonly);
|
|
||||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
|
|
||||||
view->format = const_cast<char *>(info->format.c_str());
|
|
||||||
}
|
|
||||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
|
||||||
view->ndim = (int) info->ndim;
|
|
||||||
view->strides = info->strides.data();
|
|
||||||
view->shape = info->shape.data();
|
|
||||||
}
|
|
||||||
Py_INCREF(view->obj);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// buffer_protocol: Release the resources of the buffer.
|
|
||||||
extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
|
|
||||||
delete (buffer_info *) view->internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Give this type a buffer interface.
|
|
||||||
inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
|
|
||||||
heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
|
|
||||||
|
|
||||||
heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
|
|
||||||
heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a brand new Python type according to the `type_record` specification.
|
|
||||||
Return value: New reference. */
|
|
||||||
inline PyObject *make_new_python_type(const type_record &rec) {
|
|
||||||
auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
|
|
||||||
|
|
||||||
auto qualname = name;
|
|
||||||
if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) {
|
|
||||||
qualname = reinterpret_steal<object>(
|
|
||||||
PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
|
|
||||||
}
|
|
||||||
|
|
||||||
object module_;
|
|
||||||
if (rec.scope) {
|
|
||||||
if (hasattr(rec.scope, "__module__")) {
|
|
||||||
module_ = rec.scope.attr("__module__");
|
|
||||||
} else if (hasattr(rec.scope, "__name__")) {
|
|
||||||
module_ = rec.scope.attr("__name__");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto *full_name = c_str(
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
module_ ? str(module_).cast<std::string>() + "." + rec.name :
|
|
||||||
#endif
|
|
||||||
rec.name);
|
|
||||||
|
|
||||||
char *tp_doc = nullptr;
|
|
||||||
if (rec.doc && options::show_user_defined_docstrings()) {
|
|
||||||
/* Allocate memory for docstring (using PyObject_MALLOC, since
|
|
||||||
Python will free this later on) */
|
|
||||||
size_t size = std::strlen(rec.doc) + 1;
|
|
||||||
tp_doc = (char *) PyObject_MALLOC(size);
|
|
||||||
std::memcpy((void *) tp_doc, rec.doc, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &internals = get_internals();
|
|
||||||
auto bases = tuple(rec.bases);
|
|
||||||
auto *base = (bases.empty()) ? internals.instance_base : bases[0].ptr();
|
|
||||||
|
|
||||||
/* Danger zone: from now (and until PyType_Ready), make sure to
|
|
||||||
issue no Python C API calls which could potentially invoke the
|
|
||||||
garbage collector (the GC will call type_traverse(), which will in
|
|
||||||
turn find the newly constructed type in an invalid state) */
|
|
||||||
auto *metaclass
|
|
||||||
= rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() : internals.default_metaclass;
|
|
||||||
|
|
||||||
auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
|
|
||||||
if (!heap_type) {
|
|
||||||
pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_type->ht_name = name.release().ptr();
|
|
||||||
#ifdef PYBIND11_BUILTIN_QUALNAME
|
|
||||||
heap_type->ht_qualname = qualname.inc_ref().ptr();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto *type = &heap_type->ht_type;
|
|
||||||
type->tp_name = full_name;
|
|
||||||
type->tp_doc = tp_doc;
|
|
||||||
type->tp_base = type_incref((PyTypeObject *) base);
|
|
||||||
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
|
|
||||||
if (!bases.empty()) {
|
|
||||||
type->tp_bases = bases.release().ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't inherit base __init__ */
|
|
||||||
type->tp_init = pybind11_object_init;
|
|
||||||
|
|
||||||
/* Supported protocols */
|
|
||||||
type->tp_as_number = &heap_type->as_number;
|
|
||||||
type->tp_as_sequence = &heap_type->as_sequence;
|
|
||||||
type->tp_as_mapping = &heap_type->as_mapping;
|
|
||||||
type->tp_as_async = &heap_type->as_async;
|
|
||||||
|
|
||||||
/* Flags */
|
|
||||||
type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
|
|
||||||
if (!rec.is_final) {
|
|
||||||
type->tp_flags |= Py_TPFLAGS_BASETYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rec.dynamic_attr) {
|
|
||||||
enable_dynamic_attributes(heap_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rec.buffer_protocol) {
|
|
||||||
enable_buffer_protocol(heap_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rec.custom_type_setup_callback) {
|
|
||||||
rec.custom_type_setup_callback(heap_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyType_Ready(type) < 0) {
|
|
||||||
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed: " + error_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
|
|
||||||
|
|
||||||
/* Register type with the parent scope */
|
|
||||||
if (rec.scope) {
|
|
||||||
setattr(rec.scope, rec.name, (PyObject *) type);
|
|
||||||
} else {
|
|
||||||
Py_INCREF(type); // Keep it alive forever (reference leak)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (module_) { // Needed by pydoc
|
|
||||||
setattr((PyObject *) type, "__module__", module_);
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
|
||||||
|
|
||||||
return (PyObject *) type;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
1255
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
1255
3rdparty/pybind11/include/pybind11/detail/common.h
vendored
File diff suppressed because it is too large
Load Diff
171
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
171
3rdparty/pybind11/include/pybind11/detail/descr.h
vendored
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
|
||||||
# define PYBIND11_DESCR_CONSTEXPR static constexpr
|
|
||||||
#else
|
|
||||||
# define PYBIND11_DESCR_CONSTEXPR const
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Concatenate type signatures at compile time */
|
|
||||||
template <size_t N, typename... Ts>
|
|
||||||
struct descr {
|
|
||||||
char text[N + 1]{'\0'};
|
|
||||||
|
|
||||||
constexpr descr() = default;
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {}
|
|
||||||
|
|
||||||
template <size_t... Is>
|
|
||||||
constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\0'} {}
|
|
||||||
|
|
||||||
template <typename... Chars>
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} {}
|
|
||||||
|
|
||||||
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
|
|
||||||
return {{&typeid(Ts)..., nullptr}};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
|
|
||||||
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,
|
|
||||||
const descr<N2, Ts2...> &b,
|
|
||||||
index_sequence<Is1...>,
|
|
||||||
index_sequence<Is2...>) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
|
|
||||||
return {a.text[Is1]..., b.text[Is2]...};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
|
||||||
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,
|
|
||||||
const descr<N2, Ts2...> &b) {
|
|
||||||
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N>
|
|
||||||
constexpr descr<N - 1> const_name(char const (&text)[N]) {
|
|
||||||
return descr<N - 1>(text);
|
|
||||||
}
|
|
||||||
constexpr descr<0> const_name(char const (&)[1]) { return {}; }
|
|
||||||
|
|
||||||
template <size_t Rem, size_t... Digits>
|
|
||||||
struct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};
|
|
||||||
template <size_t... Digits>
|
|
||||||
struct int_to_str<0, Digits...> {
|
|
||||||
// WARNING: This only works with C++17 or higher.
|
|
||||||
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ternary description (like std::conditional)
|
|
||||||
template <bool B, size_t N1, size_t N2>
|
|
||||||
constexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {
|
|
||||||
return const_name(text1);
|
|
||||||
}
|
|
||||||
template <bool B, size_t N1, size_t N2>
|
|
||||||
constexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {
|
|
||||||
return const_name(text2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool B, typename T1, typename T2>
|
|
||||||
constexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
template <bool B, typename T1, typename T2>
|
|
||||||
constexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t Size>
|
|
||||||
auto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
|
|
||||||
return int_to_str<Size / 10, Size % 10>::digits;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
constexpr descr<1, Type> const_name() {
|
|
||||||
return {'%'};
|
|
||||||
}
|
|
||||||
|
|
||||||
// If "_" is defined as a macro, py::detail::_ cannot be provided.
|
|
||||||
// It is therefore best to use py::detail::const_name universally.
|
|
||||||
// This block is for backward compatibility only.
|
|
||||||
// (The const_name code is repeated to avoid introducing a "_" #define ourselves.)
|
|
||||||
#ifndef _
|
|
||||||
# define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
|
|
||||||
template <size_t N>
|
|
||||||
constexpr descr<N - 1> _(char const (&text)[N]) {
|
|
||||||
return const_name<N>(text);
|
|
||||||
}
|
|
||||||
template <bool B, size_t N1, size_t N2>
|
|
||||||
constexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
|
|
||||||
return const_name<B, N1, N2>(text1, text2);
|
|
||||||
}
|
|
||||||
template <bool B, size_t N1, size_t N2>
|
|
||||||
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {
|
|
||||||
return const_name<B, N1, N2>(text1, text2);
|
|
||||||
}
|
|
||||||
template <bool B, typename T1, typename T2>
|
|
||||||
constexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {
|
|
||||||
return const_name<B, T1, T2>(d1, d2);
|
|
||||||
}
|
|
||||||
template <bool B, typename T1, typename T2>
|
|
||||||
constexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {
|
|
||||||
return const_name<B, T1, T2>(d1, d2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t Size>
|
|
||||||
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
|
|
||||||
return const_name<Size>();
|
|
||||||
}
|
|
||||||
template <typename Type>
|
|
||||||
constexpr descr<1, Type> _() {
|
|
||||||
return const_name<Type>();
|
|
||||||
}
|
|
||||||
#endif // #ifndef _
|
|
||||||
|
|
||||||
constexpr descr<0> concat() { return {}; }
|
|
||||||
|
|
||||||
template <size_t N, typename... Ts>
|
|
||||||
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
|
|
||||||
return descr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cpp_fold_expressions
|
|
||||||
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2>
|
|
||||||
constexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a,
|
|
||||||
const descr<N2, Ts2...> &b) {
|
|
||||||
return a + const_name(", ") + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N, typename... Ts, typename... Args>
|
|
||||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
|
|
||||||
return (d, ..., args);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template <size_t N, typename... Ts, typename... Args>
|
|
||||||
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
|
|
||||||
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
|
|
||||||
return d + const_name(", ") + concat(args...);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <size_t N, typename... Ts>
|
|
||||||
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
|
|
||||||
return const_name("{") + descr + const_name("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
434
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
434
3rdparty/pybind11/include/pybind11/detail/init.h
vendored
@ -1,434 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/init.h: init factory function implementation and support code.
|
|
||||||
|
|
||||||
Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "class.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class type_caster<value_and_holder> {
|
|
||||||
public:
|
|
||||||
bool load(handle h, bool) {
|
|
||||||
value = reinterpret_cast<value_and_holder *>(h.ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename>
|
|
||||||
using cast_op_type = value_and_holder &;
|
|
||||||
explicit operator value_and_holder &() { return *value; }
|
|
||||||
static constexpr auto name = const_name<value_and_holder>();
|
|
||||||
|
|
||||||
private:
|
|
||||||
value_and_holder *value = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(initimpl)
|
|
||||||
|
|
||||||
inline void no_nullptr(void *ptr) {
|
|
||||||
if (!ptr) {
|
|
||||||
throw type_error("pybind11::init(): factory function returned nullptr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementing functions for all forms of py::init<...> and py::init(...)
|
|
||||||
template <typename Class>
|
|
||||||
using Cpp = typename Class::type;
|
|
||||||
template <typename Class>
|
|
||||||
using Alias = typename Class::type_alias;
|
|
||||||
template <typename Class>
|
|
||||||
using Holder = typename Class::holder_type;
|
|
||||||
|
|
||||||
template <typename Class>
|
|
||||||
using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
|
|
||||||
|
|
||||||
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
|
|
||||||
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
|
||||||
bool is_alias(Cpp<Class> *ptr) {
|
|
||||||
return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
|
|
||||||
}
|
|
||||||
// Failing fallback version of the above for a no-alias class (always returns false)
|
|
||||||
template <typename /*Class*/>
|
|
||||||
constexpr bool is_alias(void *) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
|
|
||||||
// back to brace aggregate initiailization so that for aggregate initialization can be used with
|
|
||||||
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
|
|
||||||
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
|
|
||||||
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
|
|
||||||
template <typename Class,
|
|
||||||
typename... Args,
|
|
||||||
detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
|
|
||||||
inline Class *construct_or_initialize(Args &&...args) {
|
|
||||||
return new Class(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
template <typename Class,
|
|
||||||
typename... Args,
|
|
||||||
detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
|
|
||||||
inline Class *construct_or_initialize(Args &&...args) {
|
|
||||||
return new Class{std::forward<Args>(args)...};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
|
|
||||||
// an alias to provide only a single Cpp factory function as long as the Alias can be
|
|
||||||
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
|
|
||||||
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
|
|
||||||
// inherit all the base class constructors.
|
|
||||||
template <typename Class>
|
|
||||||
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
|
|
||||||
value_and_holder &v_h,
|
|
||||||
Cpp<Class> &&base) {
|
|
||||||
v_h.value_ptr() = new Alias<Class>(std::move(base));
|
|
||||||
}
|
|
||||||
template <typename Class>
|
|
||||||
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
|
|
||||||
value_and_holder &,
|
|
||||||
Cpp<Class> &&) {
|
|
||||||
throw type_error("pybind11::init(): unable to convert returned instance to required "
|
|
||||||
"alias class: no `Alias<Class>(Class &&)` constructor available");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error-generating fallback for factories that don't match one of the below construction
|
|
||||||
// mechanisms.
|
|
||||||
template <typename Class>
|
|
||||||
void construct(...) {
|
|
||||||
static_assert(!std::is_same<Class, Class>::value /* always false */,
|
|
||||||
"pybind11::init(): init function must return a compatible pointer, "
|
|
||||||
"holder, or value");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer return v1: the factory function returns a class pointer for a registered class.
|
|
||||||
// If we don't need an alias (because this class doesn't have one, or because the final type is
|
|
||||||
// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to
|
|
||||||
// construct an Alias from the returned base instance.
|
|
||||||
template <typename Class>
|
|
||||||
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
|
||||||
no_nullptr(ptr);
|
|
||||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
|
||||||
// We're going to try to construct an alias by moving the cpp type. Whether or not
|
|
||||||
// that succeeds, we still need to destroy the original cpp pointer (either the
|
|
||||||
// moved away leftover, if the alias construction works, or the value itself if we
|
|
||||||
// throw an error), but we can't just call `delete ptr`: it might have a special
|
|
||||||
// deleter, or might be shared_from_this. So we construct a holder around it as if
|
|
||||||
// it was a normal instance, then steal the holder away into a local variable; thus
|
|
||||||
// the holder and destruction happens when we leave the C++ scope, and the holder
|
|
||||||
// class gets to handle the destruction however it likes.
|
|
||||||
v_h.value_ptr() = ptr;
|
|
||||||
v_h.set_instance_registered(true); // To prevent init_instance from registering it
|
|
||||||
v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
|
|
||||||
Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
|
|
||||||
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
|
|
||||||
v_h.set_instance_registered(false);
|
|
||||||
|
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
|
|
||||||
} else {
|
|
||||||
// Otherwise the type isn't inherited, so we don't need an Alias
|
|
||||||
v_h.value_ptr() = ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
|
|
||||||
// ownership of the pointer.
|
|
||||||
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
|
|
||||||
void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
|
|
||||||
no_nullptr(alias_ptr);
|
|
||||||
v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
|
|
||||||
// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
|
|
||||||
// derived type (through those holder's implicit conversion from derived class holder
|
|
||||||
// constructors).
|
|
||||||
template <typename Class>
|
|
||||||
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
|
||||||
auto *ptr = holder_helper<Holder<Class>>::get(holder);
|
|
||||||
no_nullptr(ptr);
|
|
||||||
// If we need an alias, check that the held pointer is actually an alias instance
|
|
||||||
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
|
|
||||||
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
|
|
||||||
"is not an alias instance");
|
|
||||||
}
|
|
||||||
|
|
||||||
v_h.value_ptr() = ptr;
|
|
||||||
v_h.type->init_instance(v_h.inst, &holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return-by-value version 1: returning a cpp class by value. If the class has an alias and an
|
|
||||||
// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
|
|
||||||
// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
|
|
||||||
// need it, we simply move-construct the cpp value into a new instance.
|
|
||||||
template <typename Class>
|
|
||||||
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
|
||||||
static_assert(is_move_constructible<Cpp<Class>>::value,
|
|
||||||
"pybind11::init() return-by-value factory function requires a movable class");
|
|
||||||
if (Class::has_alias && need_alias) {
|
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
|
||||||
} else {
|
|
||||||
v_h.value_ptr() = new Cpp<Class>(std::move(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
|
|
||||||
// Alias instance (even if no the python-side inheritance is involved). The is intended for
|
|
||||||
// cases where Alias initialization is always desired.
|
|
||||||
template <typename Class>
|
|
||||||
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
|
||||||
static_assert(
|
|
||||||
is_move_constructible<Alias<Class>>::value,
|
|
||||||
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
|
||||||
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementing class for py::init<...>()
|
|
||||||
template <typename... Args>
|
|
||||||
struct constructor {
|
|
||||||
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
|
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[](value_and_holder &v_h, Args... args) {
|
|
||||||
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename Class,
|
|
||||||
typename... Extra,
|
|
||||||
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
|
|
||||||
= 0>
|
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[](value_and_holder &v_h, Args... args) {
|
|
||||||
if (Py_TYPE(v_h.inst) == v_h.type->type) {
|
|
||||||
v_h.value_ptr()
|
|
||||||
= construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
|
|
||||||
} else {
|
|
||||||
v_h.value_ptr()
|
|
||||||
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename Class,
|
|
||||||
typename... Extra,
|
|
||||||
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
|
|
||||||
= 0>
|
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[](value_and_holder &v_h, Args... args) {
|
|
||||||
v_h.value_ptr()
|
|
||||||
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implementing class for py::init_alias<...>()
|
|
||||||
template <typename... Args>
|
|
||||||
struct alias_constructor {
|
|
||||||
template <
|
|
||||||
typename Class,
|
|
||||||
typename... Extra,
|
|
||||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
|
|
||||||
= 0>
|
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[](value_and_holder &v_h, Args... args) {
|
|
||||||
v_h.value_ptr()
|
|
||||||
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
|
|
||||||
template <typename CFunc,
|
|
||||||
typename AFunc = void_type (*)(),
|
|
||||||
typename = function_signature_t<CFunc>,
|
|
||||||
typename = function_signature_t<AFunc>>
|
|
||||||
struct factory;
|
|
||||||
|
|
||||||
// Specialization for py::init(Func)
|
|
||||||
template <typename Func, typename Return, typename... Args>
|
|
||||||
struct factory<Func, void_type (*)(), Return(Args...)> {
|
|
||||||
remove_reference_t<Func> class_factory;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
|
|
||||||
|
|
||||||
// The given class either has no alias or has no separate alias factory;
|
|
||||||
// this always constructs the class itself. If the class is registered with an alias
|
|
||||||
// type and an alias instance is needed (i.e. because the final type is a Python class
|
|
||||||
// inheriting from the C++ type) the returned value needs to either already be an alias
|
|
||||||
// instance, or the alias needs to be constructible from a `Class &&` argument.
|
|
||||||
template <typename Class, typename... Extra>
|
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
|
||||||
#if defined(PYBIND11_CPP14)
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[func = std::move(class_factory)]
|
|
||||||
#else
|
|
||||||
auto &func = class_factory;
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[func]
|
|
||||||
#endif
|
|
||||||
(value_and_holder &v_h, Args... args) {
|
|
||||||
construct<Class>(
|
|
||||||
v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Specialization for py::init(Func, AliasFunc)
|
|
||||||
template <typename CFunc,
|
|
||||||
typename AFunc,
|
|
||||||
typename CReturn,
|
|
||||||
typename... CArgs,
|
|
||||||
typename AReturn,
|
|
||||||
typename... AArgs>
|
|
||||||
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
|
|
||||||
static_assert(sizeof...(CArgs) == sizeof...(AArgs),
|
|
||||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
|
||||||
"must have identical argument signatures");
|
|
||||||
static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
|
|
||||||
"pybind11::init(class_factory, alias_factory): class and alias factories "
|
|
||||||
"must have identical argument signatures");
|
|
||||||
|
|
||||||
remove_reference_t<CFunc> class_factory;
|
|
||||||
remove_reference_t<AFunc> alias_factory;
|
|
||||||
|
|
||||||
factory(CFunc &&c, AFunc &&a)
|
|
||||||
: class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
|
|
||||||
|
|
||||||
// The class factory is called when the `self` type passed to `__init__` is the direct
|
|
||||||
// class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
|
|
||||||
template <typename Class, typename... Extra>
|
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
|
||||||
static_assert(Class::has_alias,
|
|
||||||
"The two-argument version of `py::init()` can "
|
|
||||||
"only be used if the class has an alias");
|
|
||||||
#if defined(PYBIND11_CPP14)
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
|
|
||||||
#else
|
|
||||||
auto &class_func = class_factory;
|
|
||||||
auto &alias_func = alias_factory;
|
|
||||||
cl.def(
|
|
||||||
"__init__",
|
|
||||||
[class_func, alias_func]
|
|
||||||
#endif
|
|
||||||
(value_and_holder &v_h, CArgs... args) {
|
|
||||||
if (Py_TYPE(v_h.inst) == v_h.type->type) {
|
|
||||||
// If the instance type equals the registered type we don't have inheritance,
|
|
||||||
// so don't need the alias and can construct using the class function:
|
|
||||||
construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
|
|
||||||
} else {
|
|
||||||
construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Set just the C++ state. Same as `__init__`.
|
|
||||||
template <typename Class, typename T>
|
|
||||||
void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
|
|
||||||
construct<Class>(v_h, std::forward<T>(result), need_alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set both the C++ and Python states
|
|
||||||
template <typename Class,
|
|
||||||
typename T,
|
|
||||||
typename O,
|
|
||||||
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
|
|
||||||
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
|
|
||||||
construct<Class>(v_h, std::move(result.first), need_alias);
|
|
||||||
auto d = handle(result.second);
|
|
||||||
if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
|
|
||||||
// Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
|
|
||||||
// See PR #2972 for details.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setattr((PyObject *) v_h.inst, "__dict__", d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implementation for py::pickle(GetState, SetState)
|
|
||||||
template <typename Get,
|
|
||||||
typename Set,
|
|
||||||
typename = function_signature_t<Get>,
|
|
||||||
typename = function_signature_t<Set>>
|
|
||||||
struct pickle_factory;
|
|
||||||
|
|
||||||
template <typename Get,
|
|
||||||
typename Set,
|
|
||||||
typename RetState,
|
|
||||||
typename Self,
|
|
||||||
typename NewInstance,
|
|
||||||
typename ArgState>
|
|
||||||
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
|
|
||||||
static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
|
|
||||||
"The type returned by `__getstate__` must be the same "
|
|
||||||
"as the argument accepted by `__setstate__`");
|
|
||||||
|
|
||||||
remove_reference_t<Get> get;
|
|
||||||
remove_reference_t<Set> set;
|
|
||||||
|
|
||||||
pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
|
|
||||||
|
|
||||||
template <typename Class, typename... Extra>
|
|
||||||
void execute(Class &cl, const Extra &...extra) && {
|
|
||||||
cl.def("__getstate__", std::move(get));
|
|
||||||
|
|
||||||
#if defined(PYBIND11_CPP14)
|
|
||||||
cl.def(
|
|
||||||
"__setstate__",
|
|
||||||
[func = std::move(set)]
|
|
||||||
#else
|
|
||||||
auto &func = set;
|
|
||||||
cl.def(
|
|
||||||
"__setstate__",
|
|
||||||
[func]
|
|
||||||
#endif
|
|
||||||
(value_and_holder &v_h, ArgState state) {
|
|
||||||
setstate<Class>(
|
|
||||||
v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
|
|
||||||
},
|
|
||||||
is_new_style_constructor(),
|
|
||||||
extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(initimpl)
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -1,656 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/internals.h: Internal data structure and related functions
|
|
||||||
|
|
||||||
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
|
||||||
# include "../gil.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../pytypes.h"
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
|
|
||||||
///
|
|
||||||
/// Some portions of the code use an ABI that is conditional depending on this
|
|
||||||
/// version number. That allows ABI-breaking changes to be "pre-implemented".
|
|
||||||
/// Once the default version number is incremented, the conditional logic that
|
|
||||||
/// no longer applies can be removed. Additionally, users that need not
|
|
||||||
/// maintain ABI compatibility can increase the version number in order to take
|
|
||||||
/// advantage of any functionality/efficiency improvements that depend on the
|
|
||||||
/// newer ABI.
|
|
||||||
///
|
|
||||||
/// WARNING: If you choose to manually increase the ABI version, note that
|
|
||||||
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
|
|
||||||
/// further ABI-incompatible changes may be made before the ABI is officially
|
|
||||||
/// changed to the new version.
|
|
||||||
#ifndef PYBIND11_INTERNALS_VERSION
|
|
||||||
# if PY_VERSION_HEX >= 0x030C0000
|
|
||||||
// Version bump for Python 3.12+, before first 3.12 beta release.
|
|
||||||
# define PYBIND11_INTERNALS_VERSION 5
|
|
||||||
# else
|
|
||||||
# define PYBIND11_INTERNALS_VERSION 4
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This requirement is mainly to reduce the support burden (see PR #4570).
|
|
||||||
static_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5,
|
|
||||||
"pybind11 ABI version 5 is the minimum for Python 3.12+");
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
using ExceptionTranslator = void (*)(std::exception_ptr);
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
constexpr const char *internals_function_record_capsule_name = "pybind11_function_record_capsule";
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
inline PyTypeObject *make_static_property_type();
|
|
||||||
inline PyTypeObject *make_default_metaclass();
|
|
||||||
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
|
|
||||||
|
|
||||||
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
|
|
||||||
// Thread Specific Storage (TSS) API.
|
|
||||||
#if PY_VERSION_HEX >= 0x03070000
|
|
||||||
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
|
|
||||||
// `Py_LIMITED_API` anyway.
|
|
||||||
# if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
# define PYBIND11_TLS_KEY_REF Py_tss_t &
|
|
||||||
# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
|
||||||
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
|
|
||||||
// for every field.
|
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) \
|
|
||||||
_Pragma("GCC diagnostic push") /**/ \
|
|
||||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
|
|
||||||
Py_tss_t var \
|
|
||||||
= Py_tss_NEEDS_INIT; \
|
|
||||||
_Pragma("GCC diagnostic pop")
|
|
||||||
# else
|
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
|
|
||||||
# endif
|
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
|
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
|
|
||||||
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
|
|
||||||
# else
|
|
||||||
# define PYBIND11_TLS_KEY_REF Py_tss_t *
|
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
|
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) \
|
|
||||||
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
|
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
|
|
||||||
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
// Usually an int but a long on Cygwin64 with Python 3.x
|
|
||||||
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
|
|
||||||
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
|
|
||||||
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
|
|
||||||
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
|
|
||||||
# if defined(PYPY_VERSION)
|
|
||||||
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
|
|
||||||
// the value if it has already been set. Instead, it must first be deleted and
|
|
||||||
// then set again.
|
|
||||||
inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
|
|
||||||
PyThread_delete_key_value(key);
|
|
||||||
PyThread_set_key_value(key, value);
|
|
||||||
}
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
|
|
||||||
::pybind11::detail::tls_replace_value((key), (value))
|
|
||||||
# else
|
|
||||||
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
|
|
||||||
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
|
|
||||||
# endif
|
|
||||||
# define PYBIND11_TLS_FREE(key) (void) key
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
|
|
||||||
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
|
|
||||||
// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under
|
|
||||||
// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,
|
|
||||||
// which works. If not under a known-good stl, provide our own name-based hash and equality
|
|
||||||
// functions that use the type name.
|
|
||||||
#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__)) \
|
|
||||||
|| (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION))
|
|
||||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }
|
|
||||||
using type_hash = std::hash<std::type_index>;
|
|
||||||
using type_equal_to = std::equal_to<std::type_index>;
|
|
||||||
#else
|
|
||||||
inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {
|
|
||||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct type_hash {
|
|
||||||
size_t operator()(const std::type_index &t) const {
|
|
||||||
size_t hash = 5381;
|
|
||||||
const char *ptr = t.name();
|
|
||||||
while (auto c = static_cast<unsigned char>(*ptr++)) {
|
|
||||||
hash = (hash * 33) ^ c;
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct type_equal_to {
|
|
||||||
bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {
|
|
||||||
return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename value_type>
|
|
||||||
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
|
||||||
|
|
||||||
struct override_hash {
|
|
||||||
inline size_t operator()(const std::pair<const PyObject *, const char *> &v) const {
|
|
||||||
size_t value = std::hash<const void *>()(v.first);
|
|
||||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Internal data structure used to track registered instances and types.
|
|
||||||
/// Whenever binary incompatible changes are made to this structure,
|
|
||||||
/// `PYBIND11_INTERNALS_VERSION` must be incremented.
|
|
||||||
struct internals {
|
|
||||||
// std::type_index -> pybind11's type information
|
|
||||||
type_map<type_info *> registered_types_cpp;
|
|
||||||
// PyTypeObject* -> base type_info(s)
|
|
||||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;
|
|
||||||
std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*
|
|
||||||
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>
|
|
||||||
inactive_override_cache;
|
|
||||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
|
||||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
|
||||||
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
|
||||||
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across
|
|
||||||
// extensions
|
|
||||||
#if PYBIND11_INTERNALS_VERSION == 4
|
|
||||||
std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;
|
|
||||||
#endif
|
|
||||||
std::forward_list<std::string> static_strings; // Stores the std::strings backing
|
|
||||||
// detail::c_str()
|
|
||||||
PyTypeObject *static_property_type;
|
|
||||||
PyTypeObject *default_metaclass;
|
|
||||||
PyObject *instance_base;
|
|
||||||
#if defined(WITH_THREAD)
|
|
||||||
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
|
|
||||||
PYBIND11_TLS_KEY_INIT(tstate)
|
|
||||||
# if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
|
||||||
# endif // PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
|
|
||||||
PyInterpreterState *istate = nullptr;
|
|
||||||
|
|
||||||
# if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
// Note that we have to use a std::string to allocate memory to ensure a unique address
|
|
||||||
// We want unique addresses since we use pointer equality to compare function records
|
|
||||||
std::string function_record_capsule_name = internals_function_record_capsule_name;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
internals() = default;
|
|
||||||
internals(const internals &other) = delete;
|
|
||||||
internals &operator=(const internals &other) = delete;
|
|
||||||
~internals() {
|
|
||||||
# if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
PYBIND11_TLS_FREE(loader_life_support_tls_key);
|
|
||||||
# endif // PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
|
|
||||||
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
|
|
||||||
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
|
|
||||||
// called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does
|
|
||||||
// nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
|
|
||||||
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).
|
|
||||||
// Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*
|
|
||||||
// that the `tstate` be allocated with the CPython allocator.
|
|
||||||
PYBIND11_TLS_FREE(tstate);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Additional type information which does not fit into the PyTypeObject.
|
|
||||||
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
|
|
||||||
struct type_info {
|
|
||||||
PyTypeObject *type;
|
|
||||||
const std::type_info *cpptype;
|
|
||||||
size_t type_size, type_align, holder_size_in_ptrs;
|
|
||||||
void *(*operator_new)(size_t);
|
|
||||||
void (*init_instance)(instance *, const void *);
|
|
||||||
void (*dealloc)(value_and_holder &v_h);
|
|
||||||
std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;
|
|
||||||
std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;
|
|
||||||
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
|
|
||||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
|
||||||
void *get_buffer_data = nullptr;
|
|
||||||
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
|
||||||
/* A simple type never occurs as a (direct or indirect) parent
|
|
||||||
* of a class that makes use of multiple inheritance.
|
|
||||||
* A type can be simple even if it has non-simple ancestors as long as it has no descendants.
|
|
||||||
*/
|
|
||||||
bool simple_type : 1;
|
|
||||||
/* True if there is no multiple inheritance in this type's inheritance tree */
|
|
||||||
bool simple_ancestors : 1;
|
|
||||||
/* for base vs derived holder_type checks */
|
|
||||||
bool default_holder : 1;
|
|
||||||
/* true if this is a type registered with py::module_local */
|
|
||||||
bool module_local : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// On MSVC, debug and release builds are not ABI-compatible!
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
|
||||||
# define PYBIND11_BUILD_TYPE "_debug"
|
|
||||||
#else
|
|
||||||
# define PYBIND11_BUILD_TYPE ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Let's assume that different compilers are ABI-incompatible.
|
|
||||||
/// A user can manually set this string if they know their
|
|
||||||
/// compiler is compatible.
|
|
||||||
#ifndef PYBIND11_COMPILER_TYPE
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_msvc"
|
|
||||||
# elif defined(__INTEL_COMPILER)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_icc"
|
|
||||||
# elif defined(__clang__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_clang"
|
|
||||||
# elif defined(__PGI)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_pgi"
|
|
||||||
# elif defined(__MINGW32__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_mingw"
|
|
||||||
# elif defined(__CYGWIN__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
|
|
||||||
# elif defined(__GNUC__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_gcc"
|
|
||||||
# else
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_unknown"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Also standard libs
|
|
||||||
#ifndef PYBIND11_STDLIB
|
|
||||||
# if defined(_LIBCPP_VERSION)
|
|
||||||
# define PYBIND11_STDLIB "_libcpp"
|
|
||||||
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
|
|
||||||
# define PYBIND11_STDLIB "_libstdcpp"
|
|
||||||
# else
|
|
||||||
# define PYBIND11_STDLIB ""
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
|
|
||||||
#ifndef PYBIND11_BUILD_ABI
|
|
||||||
# if defined(__GXX_ABI_VERSION)
|
|
||||||
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
|
|
||||||
# else
|
|
||||||
# define PYBIND11_BUILD_ABI ""
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PYBIND11_INTERNALS_KIND
|
|
||||||
# if defined(WITH_THREAD)
|
|
||||||
# define PYBIND11_INTERNALS_KIND ""
|
|
||||||
# else
|
|
||||||
# define PYBIND11_INTERNALS_KIND "_without_thread"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PYBIND11_INTERNALS_ID \
|
|
||||||
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
|
||||||
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
|
||||||
PYBIND11_BUILD_TYPE "__"
|
|
||||||
|
|
||||||
#define PYBIND11_MODULE_LOCAL_ID \
|
|
||||||
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
|
||||||
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
|
||||||
PYBIND11_BUILD_TYPE "__"
|
|
||||||
|
|
||||||
/// Each module locally stores a pointer to the `internals` data. The data
|
|
||||||
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
|
||||||
inline internals **&get_internals_pp() {
|
|
||||||
static internals **internals_pp = nullptr;
|
|
||||||
return internals_pp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// forward decl
|
|
||||||
inline void translate_exception(std::exception_ptr);
|
|
||||||
|
|
||||||
template <class T,
|
|
||||||
enable_if_t<std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
|
|
||||||
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
|
||||||
std::exception_ptr nested = exc.nested_ptr();
|
|
||||||
if (nested != nullptr && nested != p) {
|
|
||||||
translate_exception(nested);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T,
|
|
||||||
enable_if_t<!std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>
|
|
||||||
bool handle_nested_exception(const T &exc, const std::exception_ptr &p) {
|
|
||||||
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(exc))) {
|
|
||||||
return handle_nested_exception(*nep, p);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool raise_err(PyObject *exc_type, const char *msg) {
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
raise_from(exc_type, msg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
PyErr_SetString(exc_type, msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void translate_exception(std::exception_ptr p) {
|
|
||||||
if (!p) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
std::rethrow_exception(p);
|
|
||||||
} catch (error_already_set &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
e.restore();
|
|
||||||
return;
|
|
||||||
} catch (const builtin_exception &e) {
|
|
||||||
// Could not use template since it's an abstract class.
|
|
||||||
if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(e))) {
|
|
||||||
handle_nested_exception(*nep, p);
|
|
||||||
}
|
|
||||||
e.set_error();
|
|
||||||
return;
|
|
||||||
} catch (const std::bad_alloc &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_MemoryError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::domain_error &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_ValueError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::invalid_argument &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_ValueError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::length_error &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_ValueError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::out_of_range &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_IndexError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::range_error &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_ValueError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::overflow_error &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_OverflowError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_RuntimeError, e.what());
|
|
||||||
return;
|
|
||||||
} catch (const std::nested_exception &e) {
|
|
||||||
handle_nested_exception(e, p);
|
|
||||||
raise_err(PyExc_RuntimeError, "Caught an unknown nested exception!");
|
|
||||||
return;
|
|
||||||
} catch (...) {
|
|
||||||
raise_err(PyExc_RuntimeError, "Caught an unknown exception!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(__GLIBCXX__)
|
|
||||||
inline void translate_local_exception(std::exception_ptr p) {
|
|
||||||
try {
|
|
||||||
if (p) {
|
|
||||||
std::rethrow_exception(p);
|
|
||||||
}
|
|
||||||
} catch (error_already_set &e) {
|
|
||||||
e.restore();
|
|
||||||
return;
|
|
||||||
} catch (const builtin_exception &e) {
|
|
||||||
e.set_error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline object get_python_state_dict() {
|
|
||||||
object state_dict;
|
|
||||||
#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
|
|
||||||
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
|
|
||||||
#else
|
|
||||||
# if PY_VERSION_HEX < 0x03090000
|
|
||||||
PyInterpreterState *istate = _PyInterpreterState_Get();
|
|
||||||
# else
|
|
||||||
PyInterpreterState *istate = PyInterpreterState_Get();
|
|
||||||
# endif
|
|
||||||
if (istate) {
|
|
||||||
state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!state_dict) {
|
|
||||||
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
|
|
||||||
}
|
|
||||||
return state_dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object get_internals_obj_from_state_dict(handle state_dict) {
|
|
||||||
return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline internals **get_internals_pp_from_capsule(handle obj) {
|
|
||||||
void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);
|
|
||||||
if (raw_ptr == nullptr) {
|
|
||||||
raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED");
|
|
||||||
}
|
|
||||||
return static_cast<internals **>(raw_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a reference to the current `internals` data
|
|
||||||
PYBIND11_NOINLINE internals &get_internals() {
|
|
||||||
auto **&internals_pp = get_internals_pp();
|
|
||||||
if (internals_pp && *internals_pp) {
|
|
||||||
return **internals_pp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WITH_THREAD)
|
|
||||||
# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
|
||||||
gil_scoped_acquire gil;
|
|
||||||
# else
|
|
||||||
// Ensure that the GIL is held since we will need to make Python calls.
|
|
||||||
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
|
|
||||||
struct gil_scoped_acquire_local {
|
|
||||||
gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}
|
|
||||||
gil_scoped_acquire_local(const gil_scoped_acquire_local &) = delete;
|
|
||||||
gil_scoped_acquire_local &operator=(const gil_scoped_acquire_local &) = delete;
|
|
||||||
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
|
||||||
const PyGILState_STATE state;
|
|
||||||
} gil;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
error_scope err_scope;
|
|
||||||
|
|
||||||
dict state_dict = get_python_state_dict();
|
|
||||||
if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) {
|
|
||||||
internals_pp = get_internals_pp_from_capsule(internals_obj);
|
|
||||||
}
|
|
||||||
if (internals_pp && *internals_pp) {
|
|
||||||
// We loaded the internals through `state_dict`, which means that our `error_already_set`
|
|
||||||
// and `builtin_exception` may be different local classes than the ones set up in the
|
|
||||||
// initial exception translator, below, so add another for our local exception classes.
|
|
||||||
//
|
|
||||||
// libstdc++ doesn't require this (types there are identified only by name)
|
|
||||||
// libc++ with CPython doesn't require this (types are explicitly exported)
|
|
||||||
// libc++ with PyPy still need it, awaiting further investigation
|
|
||||||
#if !defined(__GLIBCXX__)
|
|
||||||
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
if (!internals_pp) {
|
|
||||||
internals_pp = new internals *();
|
|
||||||
}
|
|
||||||
auto *&internals_ptr = *internals_pp;
|
|
||||||
internals_ptr = new internals();
|
|
||||||
#if defined(WITH_THREAD)
|
|
||||||
|
|
||||||
PyThreadState *tstate = PyThreadState_Get();
|
|
||||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
|
||||||
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
|
|
||||||
pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
|
|
||||||
}
|
|
||||||
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
|
|
||||||
|
|
||||||
# if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
|
||||||
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
|
|
||||||
pybind11_fail("get_internals: could not successfully initialize the "
|
|
||||||
"loader_life_support TSS key!");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
internals_ptr->istate = tstate->interp;
|
|
||||||
#endif
|
|
||||||
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
|
|
||||||
internals_ptr->registered_exception_translators.push_front(&translate_exception);
|
|
||||||
internals_ptr->static_property_type = make_static_property_type();
|
|
||||||
internals_ptr->default_metaclass = make_default_metaclass();
|
|
||||||
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
|
|
||||||
}
|
|
||||||
return **internals_pp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the internals struct (above) is shared between all the modules. local_internals are only
|
|
||||||
// for a single module. Any changes made to internals may require an update to
|
|
||||||
// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
|
|
||||||
// restricted to a single module. Whether a module has local internals or not should not
|
|
||||||
// impact any other modules, because the only things accessing the local internals is the
|
|
||||||
// module that contains them.
|
|
||||||
struct local_internals {
|
|
||||||
type_map<type_info *> registered_types_cpp;
|
|
||||||
std::forward_list<ExceptionTranslator> registered_exception_translators;
|
|
||||||
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
|
||||||
|
|
||||||
// For ABI compatibility, we can't store the loader_life_support TLS key in
|
|
||||||
// the `internals` struct directly. Instead, we store it in `shared_data` and
|
|
||||||
// cache a copy in `local_internals`. If we allocated a separate TLS key for
|
|
||||||
// each instance of `local_internals`, we could end up allocating hundreds of
|
|
||||||
// TLS keys if hundreds of different pybind11 modules are loaded (which is a
|
|
||||||
// plausible number).
|
|
||||||
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
|
||||||
|
|
||||||
// Holds the shared TLS key for the loader_life_support stack.
|
|
||||||
struct shared_loader_life_support_data {
|
|
||||||
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
|
|
||||||
shared_loader_life_support_data() {
|
|
||||||
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
|
|
||||||
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
|
|
||||||
pybind11_fail("local_internals: could not successfully initialize the "
|
|
||||||
"loader_life_support TLS key!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We can't help but leak the TLS key, because Python never unloads extension modules.
|
|
||||||
};
|
|
||||||
|
|
||||||
local_internals() {
|
|
||||||
auto &internals = get_internals();
|
|
||||||
// Get or create the `loader_life_support_stack_key`.
|
|
||||||
auto &ptr = internals.shared_data["_life_support"];
|
|
||||||
if (!ptr) {
|
|
||||||
ptr = new shared_loader_life_support_data;
|
|
||||||
}
|
|
||||||
loader_life_support_tls_key
|
|
||||||
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
|
|
||||||
}
|
|
||||||
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Works like `get_internals`, but for things which are locally registered.
|
|
||||||
inline local_internals &get_local_internals() {
|
|
||||||
// Current static can be created in the interpreter finalization routine. If the later will be
|
|
||||||
// destroyed in another static variable destructor, creation of this static there will cause
|
|
||||||
// static deinitialization fiasco. In order to avoid it we avoid destruction of the
|
|
||||||
// local_internals static. One can read more about the problem and current solution here:
|
|
||||||
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
|
|
||||||
static auto *locals = new local_internals();
|
|
||||||
return *locals;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
|
|
||||||
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
|
|
||||||
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
|
|
||||||
/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).
|
|
||||||
template <typename... Args>
|
|
||||||
const char *c_str(Args &&...args) {
|
|
||||||
auto &strings = get_internals().static_strings;
|
|
||||||
strings.emplace_front(std::forward<Args>(args)...);
|
|
||||||
return strings.front().c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *get_function_record_capsule_name() {
|
|
||||||
#if PYBIND11_INTERNALS_VERSION > 4
|
|
||||||
return get_internals().function_record_capsule_name.c_str();
|
|
||||||
#else
|
|
||||||
return nullptr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether or not the following capsule contains a pybind11 function record.
|
|
||||||
// Note that we use `internals` to make sure that only ABI compatible records are touched.
|
|
||||||
//
|
|
||||||
// This check is currently used in two places:
|
|
||||||
// - An important optimization in functional.h to avoid overhead in C++ -> Python -> C++
|
|
||||||
// - The sibling feature of cpp_function to allow overloads
|
|
||||||
inline bool is_function_record_capsule(const capsule &cap) {
|
|
||||||
// Pointer equality as we rely on internals() to ensure unique pointers
|
|
||||||
return cap.name() == get_function_record_capsule_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/// Returns a named pointer that is shared among all extension modules (using the same
|
|
||||||
/// pybind11 version) running in the current interpreter. Names starting with underscores
|
|
||||||
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
|
|
||||||
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
|
|
||||||
auto &internals = detail::get_internals();
|
|
||||||
auto it = internals.shared_data.find(name);
|
|
||||||
return it != internals.shared_data.end() ? it->second : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the shared data that can be later recovered by `get_shared_data()`.
|
|
||||||
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
|
|
||||||
detail::get_internals().shared_data[name] = data;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if
|
|
||||||
/// such entry exists. Otherwise, a new object of default-constructible type `T` is
|
|
||||||
/// added to the shared data under the given name and a reference to it is returned.
|
|
||||||
template <typename T>
|
|
||||||
T &get_or_create_shared_data(const std::string &name) {
|
|
||||||
auto &internals = detail::get_internals();
|
|
||||||
auto it = internals.shared_data.find(name);
|
|
||||||
T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);
|
|
||||||
if (!ptr) {
|
|
||||||
ptr = new T();
|
|
||||||
internals.shared_data[name] = ptr;
|
|
||||||
}
|
|
||||||
return *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/detail/typeid.h: Compiler-independent access to type identifiers
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#if defined(__GNUG__)
|
|
||||||
# include <cxxabi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/// Erase all occurrences of a substring
|
|
||||||
inline void erase_all(std::string &string, const std::string &search) {
|
|
||||||
for (size_t pos = 0;;) {
|
|
||||||
pos = string.find(search, pos);
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string.erase(pos, search.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE void clean_type_id(std::string &name) {
|
|
||||||
#if defined(__GNUG__)
|
|
||||||
int status = 0;
|
|
||||||
std::unique_ptr<char, void (*)(void *)> res{
|
|
||||||
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};
|
|
||||||
if (status == 0) {
|
|
||||||
name = res.get();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
detail::erase_all(name, "class ");
|
|
||||||
detail::erase_all(name, "struct ");
|
|
||||||
detail::erase_all(name, "enum ");
|
|
||||||
#endif
|
|
||||||
detail::erase_all(name, "pybind11::");
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string clean_type_id(const char *typeid_name) {
|
|
||||||
std::string name(typeid_name);
|
|
||||||
detail::clean_type_id(name);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/// Return a string representation of a C++ type
|
|
||||||
template <typename T>
|
|
||||||
static std::string type_id() {
|
|
||||||
return detail::clean_type_id(typeid(T).name());
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
12
3rdparty/pybind11/include/pybind11/eigen.h
vendored
12
3rdparty/pybind11/include/pybind11/eigen.h
vendored
@ -1,12 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "eigen/matrix.h"
|
|
@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) 2023 The pybind Community.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Common message for `static_assert()`s, which are useful to easily
|
|
||||||
// preempt much less obvious errors.
|
|
||||||
#define PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED \
|
|
||||||
"Pointer types (in particular `PyObject *`) are not supported as scalar types for Eigen " \
|
|
||||||
"types."
|
|
714
3rdparty/pybind11/include/pybind11/eigen/matrix.h
vendored
714
3rdparty/pybind11/include/pybind11/eigen/matrix.h
vendored
@ -1,714 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/eigen/matrix.h: Transparent conversion for dense and sparse Eigen matrices
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../numpy.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
|
|
||||||
See also:
|
|
||||||
https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
|
|
||||||
https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
|
|
||||||
*/
|
|
||||||
PYBIND11_WARNING_PUSH
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(5054) // https://github.com/pybind/pybind11/pull/3741
|
|
||||||
// C5054: operator '&': deprecated between enumerations of different types
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <Eigen/Core>
|
|
||||||
#include <Eigen/SparseCore>
|
|
||||||
|
|
||||||
PYBIND11_WARNING_POP
|
|
||||||
|
|
||||||
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
|
|
||||||
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
|
|
||||||
// of matrices seems highly undesirable.
|
|
||||||
static_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),
|
|
||||||
"Eigen matrix support in pybind11 requires Eigen >= 3.2.7");
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
|
||||||
|
|
||||||
// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
|
|
||||||
using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
|
|
||||||
template <typename MatrixType>
|
|
||||||
using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
|
|
||||||
template <typename MatrixType>
|
|
||||||
using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
|
|
||||||
using EigenIndex = Eigen::Index;
|
|
||||||
template <typename Scalar, int Flags, typename StorageIndex>
|
|
||||||
using EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;
|
|
||||||
#else
|
|
||||||
using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
|
|
||||||
template <typename Scalar, int Flags, typename StorageIndex>
|
|
||||||
using EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Matches Eigen::Map, Eigen::Ref, blocks, etc:
|
|
||||||
template <typename T>
|
|
||||||
using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,
|
|
||||||
std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
|
|
||||||
template <typename T>
|
|
||||||
using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
|
|
||||||
template <typename T>
|
|
||||||
using is_eigen_dense_plain
|
|
||||||
= all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
|
|
||||||
template <typename T>
|
|
||||||
using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
|
|
||||||
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
|
|
||||||
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
|
||||||
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
|
||||||
// SelfAdjointView fall into this category.
|
|
||||||
template <typename T>
|
|
||||||
using is_eigen_other
|
|
||||||
= all_of<is_template_base_of<Eigen::EigenBase, T>,
|
|
||||||
negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;
|
|
||||||
|
|
||||||
// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
|
|
||||||
template <bool EigenRowMajor>
|
|
||||||
struct EigenConformable {
|
|
||||||
bool conformable = false;
|
|
||||||
EigenIndex rows = 0, cols = 0;
|
|
||||||
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
|
||||||
bool negativestrides = false; // If true, do not use stride!
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
EigenConformable(bool fits = false) : conformable{fits} {}
|
|
||||||
// Matrix type:
|
|
||||||
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)
|
|
||||||
: conformable{true}, rows{r}, cols{c},
|
|
||||||
// TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.
|
|
||||||
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747
|
|
||||||
stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)
|
|
||||||
: (cstride > 0 ? cstride : 0) /* outer stride */,
|
|
||||||
EigenRowMajor ? (cstride > 0 ? cstride : 0)
|
|
||||||
: (rstride > 0 ? rstride : 0) /* inner stride */},
|
|
||||||
negativestrides{rstride < 0 || cstride < 0} {}
|
|
||||||
// Vector type:
|
|
||||||
EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
|
|
||||||
: EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}
|
|
||||||
|
|
||||||
template <typename props>
|
|
||||||
bool stride_compatible() const {
|
|
||||||
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
|
|
||||||
// matching strides, or a dimension size of 1 (in which case the stride value is
|
|
||||||
// irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
|
|
||||||
// (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
|
|
||||||
if (negativestrides) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (rows == 0 || cols == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|
|
||||||
|| (EigenRowMajor ? cols : rows) == 1)
|
|
||||||
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|
|
||||||
|| (EigenRowMajor ? rows : cols) == 1);
|
|
||||||
}
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator bool() const { return conformable; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct eigen_extract_stride {
|
|
||||||
using type = Type;
|
|
||||||
};
|
|
||||||
template <typename PlainObjectType, int MapOptions, typename StrideType>
|
|
||||||
struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {
|
|
||||||
using type = StrideType;
|
|
||||||
};
|
|
||||||
template <typename PlainObjectType, int Options, typename StrideType>
|
|
||||||
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {
|
|
||||||
using type = StrideType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper struct for extracting information from an Eigen type
|
|
||||||
template <typename Type_>
|
|
||||||
struct EigenProps {
|
|
||||||
using Type = Type_;
|
|
||||||
using Scalar = typename Type::Scalar;
|
|
||||||
using StrideType = typename eigen_extract_stride<Type>::type;
|
|
||||||
static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,
|
|
||||||
size = Type::SizeAtCompileTime;
|
|
||||||
static constexpr bool row_major = Type::IsRowMajor,
|
|
||||||
vector
|
|
||||||
= Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
|
|
||||||
fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,
|
|
||||||
fixed = size != Eigen::Dynamic, // Fully-fixed size
|
|
||||||
dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
|
|
||||||
|
|
||||||
template <EigenIndex i, EigenIndex ifzero>
|
|
||||||
using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
|
|
||||||
static constexpr EigenIndex inner_stride
|
|
||||||
= if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
|
|
||||||
outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,
|
|
||||||
vector ? size
|
|
||||||
: row_major ? cols
|
|
||||||
: rows > ::value;
|
|
||||||
static constexpr bool dynamic_stride
|
|
||||||
= inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
|
|
||||||
static constexpr bool requires_row_major
|
|
||||||
= !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
|
|
||||||
static constexpr bool requires_col_major
|
|
||||||
= !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
|
|
||||||
|
|
||||||
// Takes an input array and determines whether we can make it fit into the Eigen type. If
|
|
||||||
// the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
|
|
||||||
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
|
|
||||||
static EigenConformable<row_major> conformable(const array &a) {
|
|
||||||
const auto dims = a.ndim();
|
|
||||||
if (dims < 1 || dims > 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dims == 2) { // Matrix type: require exact match (or dynamic)
|
|
||||||
|
|
||||||
EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),
|
|
||||||
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
|
|
||||||
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
|
|
||||||
if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {np_rows, np_cols, np_rstride, np_cstride};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we're storing an n-vector. Only one of the strides will be used, but
|
|
||||||
// whichever is used, we want the (single) numpy stride value.
|
|
||||||
const EigenIndex n = a.shape(0),
|
|
||||||
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
|
|
||||||
|
|
||||||
if (vector) { // Eigen type is a compile-time vector
|
|
||||||
if (fixed && size != n) {
|
|
||||||
return false; // Vector size mismatch
|
|
||||||
}
|
|
||||||
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
|
|
||||||
}
|
|
||||||
if (fixed) {
|
|
||||||
// The type has a fixed size, but is not a vector: abort
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (fixed_cols) {
|
|
||||||
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
|
|
||||||
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
|
|
||||||
if (cols != n) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return {1, n, stride};
|
|
||||||
} // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
|
|
||||||
if (fixed_rows && rows != n) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return {n, 1, stride};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr bool show_writeable
|
|
||||||
= is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
|
|
||||||
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
|
|
||||||
static constexpr bool show_c_contiguous = show_order && requires_row_major;
|
|
||||||
static constexpr bool show_f_contiguous
|
|
||||||
= !show_c_contiguous && show_order && requires_col_major;
|
|
||||||
|
|
||||||
static constexpr auto descriptor
|
|
||||||
= const_name("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + const_name("[")
|
|
||||||
+ const_name<fixed_rows>(const_name<(size_t) rows>(), const_name("m")) + const_name(", ")
|
|
||||||
+ const_name<fixed_cols>(const_name<(size_t) cols>(), const_name("n")) + const_name("]")
|
|
||||||
+
|
|
||||||
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to
|
|
||||||
// be satisfied: writeable=True (for a mutable reference), and, depending on the map's
|
|
||||||
// stride options, possibly f_contiguous or c_contiguous. We include them in the
|
|
||||||
// descriptor output to provide some hint as to why a TypeError is occurring (otherwise
|
|
||||||
// it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and
|
|
||||||
// an error message that you *gave* a numpy.ndarray of the right type and dimensions.
|
|
||||||
const_name<show_writeable>(", flags.writeable", "")
|
|
||||||
+ const_name<show_c_contiguous>(", flags.c_contiguous", "")
|
|
||||||
+ const_name<show_f_contiguous>(", flags.f_contiguous", "") + const_name("]");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
|
||||||
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
|
||||||
template <typename props>
|
|
||||||
handle
|
|
||||||
eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
|
||||||
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
|
||||||
array a;
|
|
||||||
if (props::vector) {
|
|
||||||
a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);
|
|
||||||
} else {
|
|
||||||
a = array({src.rows(), src.cols()},
|
|
||||||
{elem_size * src.rowStride(), elem_size * src.colStride()},
|
|
||||||
src.data(),
|
|
||||||
base);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!writeable) {
|
|
||||||
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
|
|
||||||
// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
|
|
||||||
// the base will be set to None, and lifetime management is up to the caller). The numpy array is
|
|
||||||
// non-writeable if the given type is const.
|
|
||||||
template <typename props, typename Type>
|
|
||||||
handle eigen_ref_array(Type &src, handle parent = none()) {
|
|
||||||
// none here is to get past array's should-we-copy detection, which currently always
|
|
||||||
// copies when there is no base. Setting the base to None should be harmless.
|
|
||||||
return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a
|
|
||||||
// numpy array that references the encapsulated data with a python-side reference to the capsule to
|
|
||||||
// tie its destruction to that of any dependent python objects. Const-ness is determined by
|
|
||||||
// whether or not the Type of the pointer given is const.
|
|
||||||
template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
|
|
||||||
handle eigen_encapsulate(Type *src) {
|
|
||||||
capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
|
|
||||||
return eigen_ref_array<props>(*src, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
|
|
||||||
// types.
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
|
|
||||||
using Scalar = typename Type::Scalar;
|
|
||||||
static_assert(!std::is_pointer<Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
using props = EigenProps<Type>;
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
// If we're in no-convert mode, only load if given an array of the correct type
|
|
||||||
if (!convert && !isinstance<array_t<Scalar>>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
|
|
||||||
auto buf = array::ensure(src);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dims = buf.ndim();
|
|
||||||
if (dims < 1 || dims > 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fits = props::conformable(buf);
|
|
||||||
if (!fits) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate the new type, then build a numpy reference into it
|
|
||||||
value = Type(fits.rows, fits.cols);
|
|
||||||
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
|
|
||||||
if (dims == 1) {
|
|
||||||
ref = ref.squeeze();
|
|
||||||
} else if (ref.ndim() == 1) {
|
|
||||||
buf = buf.squeeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
|
|
||||||
|
|
||||||
if (result < 0) { // Copy failed!
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Cast implementation
|
|
||||||
template <typename CType>
|
|
||||||
static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
|
|
||||||
switch (policy) {
|
|
||||||
case return_value_policy::take_ownership:
|
|
||||||
case return_value_policy::automatic:
|
|
||||||
return eigen_encapsulate<props>(src);
|
|
||||||
case return_value_policy::move:
|
|
||||||
return eigen_encapsulate<props>(new CType(std::move(*src)));
|
|
||||||
case return_value_policy::copy:
|
|
||||||
return eigen_array_cast<props>(*src);
|
|
||||||
case return_value_policy::reference:
|
|
||||||
case return_value_policy::automatic_reference:
|
|
||||||
return eigen_ref_array<props>(*src);
|
|
||||||
case return_value_policy::reference_internal:
|
|
||||||
return eigen_ref_array<props>(*src, parent);
|
|
||||||
default:
|
|
||||||
throw cast_error("unhandled return_value_policy: should not happen!");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Normal returned non-reference, non-const value:
|
|
||||||
static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
|
|
||||||
return cast_impl(&src, return_value_policy::move, parent);
|
|
||||||
}
|
|
||||||
// If you return a non-reference const, we mark the numpy array readonly:
|
|
||||||
static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
|
|
||||||
return cast_impl(&src, return_value_policy::move, parent);
|
|
||||||
}
|
|
||||||
// lvalue reference return; default (automatic) becomes copy
|
|
||||||
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast_impl(&src, policy, parent);
|
|
||||||
}
|
|
||||||
// const lvalue reference return; default (automatic) becomes copy
|
|
||||||
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast(&src, policy, parent);
|
|
||||||
}
|
|
||||||
// non-const pointer return
|
|
||||||
static handle cast(Type *src, return_value_policy policy, handle parent) {
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
// const pointer return
|
|
||||||
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto name = props::descriptor;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator Type *() { return &value; }
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator Type &() { return value; }
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator Type &&() && { return std::move(value); }
|
|
||||||
template <typename T>
|
|
||||||
using cast_op_type = movable_cast_op_type<T>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Base class for casting reference/map/block/etc. objects back to python.
|
|
||||||
template <typename MapType>
|
|
||||||
struct eigen_map_caster {
|
|
||||||
static_assert(!std::is_pointer<typename MapType::Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
private:
|
|
||||||
using props = EigenProps<MapType>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
|
|
||||||
// to stay around), but we'll allow it under the assumption that you know what you're doing
|
|
||||||
// (and have an appropriate keep_alive in place). We return a numpy array pointing directly at
|
|
||||||
// the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)
|
|
||||||
// Note that this means you need to ensure you don't destroy the object in some other way (e.g.
|
|
||||||
// with an appropriate keep_alive, or with a reference to a statically allocated matrix).
|
|
||||||
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
|
||||||
switch (policy) {
|
|
||||||
case return_value_policy::copy:
|
|
||||||
return eigen_array_cast<props>(src);
|
|
||||||
case return_value_policy::reference_internal:
|
|
||||||
return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
|
|
||||||
case return_value_policy::reference:
|
|
||||||
case return_value_policy::automatic:
|
|
||||||
case return_value_policy::automatic_reference:
|
|
||||||
return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
|
|
||||||
default:
|
|
||||||
// move, take_ownership don't make any sense for a ref/map:
|
|
||||||
pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto name = props::descriptor;
|
|
||||||
|
|
||||||
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
|
||||||
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
|
||||||
// you end up here if you try anyway.
|
|
||||||
bool load(handle, bool) = delete;
|
|
||||||
operator MapType() = delete;
|
|
||||||
template <typename>
|
|
||||||
using cast_op_type = MapType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We can return any map-like object (but can only load Refs, specialized next):
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};
|
|
||||||
|
|
||||||
// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
|
|
||||||
// copying (it requires some extra effort in many cases).
|
|
||||||
template <typename PlainObjectType, typename StrideType>
|
|
||||||
struct type_caster<
|
|
||||||
Eigen::Ref<PlainObjectType, 0, StrideType>,
|
|
||||||
enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>
|
|
||||||
: public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
|
|
||||||
private:
|
|
||||||
using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
|
|
||||||
using props = EigenProps<Type>;
|
|
||||||
using Scalar = typename props::Scalar;
|
|
||||||
static_assert(!std::is_pointer<Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
|
|
||||||
using Array
|
|
||||||
= array_t<Scalar,
|
|
||||||
array::forcecast
|
|
||||||
| ((props::row_major ? props::inner_stride : props::outer_stride) == 1
|
|
||||||
? array::c_style
|
|
||||||
: (props::row_major ? props::outer_stride : props::inner_stride) == 1
|
|
||||||
? array::f_style
|
|
||||||
: 0)>;
|
|
||||||
static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
|
|
||||||
// Delay construction (these have no default constructor)
|
|
||||||
std::unique_ptr<MapType> map;
|
|
||||||
std::unique_ptr<Type> ref;
|
|
||||||
// Our array. When possible, this is just a numpy array pointing to the source data, but
|
|
||||||
// sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an
|
|
||||||
// incompatible layout, or is an array of a type that needs to be converted). Using a numpy
|
|
||||||
// temporary (rather than an Eigen temporary) saves an extra copy when we need both type
|
|
||||||
// conversion and storage order conversion. (Note that we refuse to use this temporary copy
|
|
||||||
// when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).
|
|
||||||
Array copy_or_ref;
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
// First check whether what we have is already an array of the right type. If not, we
|
|
||||||
// can't avoid a copy (because the copy is also going to do type conversion).
|
|
||||||
bool need_copy = !isinstance<Array>(src);
|
|
||||||
|
|
||||||
EigenConformable<props::row_major> fits;
|
|
||||||
if (!need_copy) {
|
|
||||||
// We don't need a converting copy, but we also need to check whether the strides are
|
|
||||||
// compatible with the Ref's stride requirements
|
|
||||||
auto aref = reinterpret_borrow<Array>(src);
|
|
||||||
|
|
||||||
if (aref && (!need_writeable || aref.writeable())) {
|
|
||||||
fits = props::conformable(aref);
|
|
||||||
if (!fits) {
|
|
||||||
return false; // Incompatible dimensions
|
|
||||||
}
|
|
||||||
if (!fits.template stride_compatible<props>()) {
|
|
||||||
need_copy = true;
|
|
||||||
} else {
|
|
||||||
copy_or_ref = std::move(aref);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
need_copy = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (need_copy) {
|
|
||||||
// We need to copy: If we need a mutable reference, or we're not supposed to convert
|
|
||||||
// (either because we're in the no-convert overload pass, or because we're explicitly
|
|
||||||
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
|
|
||||||
if (!convert || need_writeable) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array copy = Array::ensure(src);
|
|
||||||
if (!copy) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fits = props::conformable(copy);
|
|
||||||
if (!fits || !fits.template stride_compatible<props>()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
copy_or_ref = std::move(copy);
|
|
||||||
loader_life_support::add_patient(copy_or_ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.reset();
|
|
||||||
map.reset(new MapType(data(copy_or_ref),
|
|
||||||
fits.rows,
|
|
||||||
fits.cols,
|
|
||||||
make_stride(fits.stride.outer(), fits.stride.inner())));
|
|
||||||
ref.reset(new Type(*map));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator Type *() { return ref.get(); }
|
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
||||||
operator Type &() { return *ref; }
|
|
||||||
template <typename _T>
|
|
||||||
using cast_op_type = pybind11::detail::cast_op_type<_T>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
|
|
||||||
Scalar *data(Array &a) {
|
|
||||||
return a.mutable_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
|
|
||||||
const Scalar *data(Array &a) {
|
|
||||||
return a.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to figure out a constructor of `Stride` that will work.
|
|
||||||
// If both strides are fixed, use a default constructor:
|
|
||||||
template <typename S>
|
|
||||||
using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic
|
|
||||||
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
|
|
||||||
&& std::is_default_constructible<S>::value>;
|
|
||||||
// Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
|
|
||||||
// Eigen::Stride, and use it:
|
|
||||||
template <typename S>
|
|
||||||
using stride_ctor_dual
|
|
||||||
= bool_constant<!stride_ctor_default<S>::value
|
|
||||||
&& std::is_constructible<S, EigenIndex, EigenIndex>::value>;
|
|
||||||
// Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
|
|
||||||
// it (passing whichever stride is dynamic).
|
|
||||||
template <typename S>
|
|
||||||
using stride_ctor_outer
|
|
||||||
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
|
|
||||||
&& S::OuterStrideAtCompileTime == Eigen::Dynamic
|
|
||||||
&& S::InnerStrideAtCompileTime != Eigen::Dynamic
|
|
||||||
&& std::is_constructible<S, EigenIndex>::value>;
|
|
||||||
template <typename S>
|
|
||||||
using stride_ctor_inner
|
|
||||||
= bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value
|
|
||||||
&& S::InnerStrideAtCompileTime == Eigen::Dynamic
|
|
||||||
&& S::OuterStrideAtCompileTime != Eigen::Dynamic
|
|
||||||
&& std::is_constructible<S, EigenIndex>::value>;
|
|
||||||
|
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
|
|
||||||
static S make_stride(EigenIndex, EigenIndex) {
|
|
||||||
return S();
|
|
||||||
}
|
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
|
|
||||||
static S make_stride(EigenIndex outer, EigenIndex inner) {
|
|
||||||
return S(outer, inner);
|
|
||||||
}
|
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
|
|
||||||
static S make_stride(EigenIndex outer, EigenIndex) {
|
|
||||||
return S(outer);
|
|
||||||
}
|
|
||||||
template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
|
|
||||||
static S make_stride(EigenIndex, EigenIndex inner) {
|
|
||||||
return S(inner);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
|
|
||||||
// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
|
|
||||||
// load() is not supported, but we can cast them into the python domain by first copying to a
|
|
||||||
// regular Eigen::Matrix, then casting that.
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
|
|
||||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
using Matrix
|
|
||||||
= Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
|
|
||||||
using props = EigenProps<Matrix>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
|
||||||
handle h = eigen_encapsulate<props>(new Matrix(src));
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
|
||||||
return cast(*src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto name = props::descriptor;
|
|
||||||
|
|
||||||
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
|
|
||||||
// types but not bound arguments). We still provide them (with an explicitly delete) so that
|
|
||||||
// you end up here if you try anyway.
|
|
||||||
bool load(handle, bool) = delete;
|
|
||||||
operator Type() = delete;
|
|
||||||
template <typename>
|
|
||||||
using cast_op_type = Type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|
||||||
using Scalar = typename Type::Scalar;
|
|
||||||
static_assert(!std::is_pointer<Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;
|
|
||||||
using Index = typename Type::Index;
|
|
||||||
static constexpr bool rowMajor = Type::IsRowMajor;
|
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
|
||||||
if (!src) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto obj = reinterpret_borrow<object>(src);
|
|
||||||
object sparse_module = module_::import("scipy.sparse");
|
|
||||||
object matrix_type = sparse_module.attr(rowMajor ? "csr_matrix" : "csc_matrix");
|
|
||||||
|
|
||||||
if (!type::handle_of(obj).is(matrix_type)) {
|
|
||||||
try {
|
|
||||||
obj = matrix_type(obj);
|
|
||||||
} catch (const error_already_set &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto values = array_t<Scalar>((object) obj.attr("data"));
|
|
||||||
auto innerIndices = array_t<StorageIndex>((object) obj.attr("indices"));
|
|
||||||
auto outerIndices = array_t<StorageIndex>((object) obj.attr("indptr"));
|
|
||||||
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
|
|
||||||
auto nnz = obj.attr("nnz").cast<Index>();
|
|
||||||
|
|
||||||
if (!values || !innerIndices || !outerIndices) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = EigenMapSparseMatrix<Scalar,
|
|
||||||
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
|
|
||||||
StorageIndex>(shape[0].cast<Index>(),
|
|
||||||
shape[1].cast<Index>(),
|
|
||||||
std::move(nnz),
|
|
||||||
outerIndices.mutable_data(),
|
|
||||||
innerIndices.mutable_data(),
|
|
||||||
values.mutable_data());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
|
||||||
const_cast<Type &>(src).makeCompressed();
|
|
||||||
|
|
||||||
object matrix_type
|
|
||||||
= module_::import("scipy.sparse").attr(rowMajor ? "csr_matrix" : "csc_matrix");
|
|
||||||
|
|
||||||
array data(src.nonZeros(), src.valuePtr());
|
|
||||||
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
|
||||||
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
|
||||||
|
|
||||||
return matrix_type(pybind11::make_tuple(
|
|
||||||
std::move(data), std::move(innerIndices), std::move(outerIndices)),
|
|
||||||
pybind11::make_tuple(src.rows(), src.cols()))
|
|
||||||
.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type,
|
|
||||||
const_name<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[",
|
|
||||||
"scipy.sparse.csc_matrix[")
|
|
||||||
+ npy_format_descriptor<Scalar>::name + const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
516
3rdparty/pybind11/include/pybind11/eigen/tensor.h
vendored
516
3rdparty/pybind11/include/pybind11/eigen/tensor.h
vendored
@ -1,516 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/eigen/tensor.h: Transparent conversion for Eigen tensors
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../numpy.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
|
||||||
static_assert(__GNUC__ > 5, "Eigen Tensor support in pybind11 requires GCC > 5.0");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Disable warnings for Eigen
|
|
||||||
PYBIND11_WARNING_PUSH
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4554)
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unsupported/Eigen/CXX11/Tensor>
|
|
||||||
|
|
||||||
PYBIND11_WARNING_POP
|
|
||||||
|
|
||||||
static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),
|
|
||||||
"Eigen Tensor support in pybind11 requires Eigen >= 3.3.0");
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_WARNING_DISABLE_MSVC(4127)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
inline bool is_tensor_aligned(const void *data) {
|
|
||||||
return (reinterpret_cast<std::size_t>(data) % EIGEN_DEFAULT_ALIGN_BYTES) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr int compute_array_flag_from_tensor() {
|
|
||||||
static_assert((static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor))
|
|
||||||
|| (static_cast<int>(T::Layout) == static_cast<int>(Eigen::ColMajor)),
|
|
||||||
"Layout must be row or column major");
|
|
||||||
return (static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor)) ? array::c_style
|
|
||||||
: array::f_style;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct eigen_tensor_helper {};
|
|
||||||
|
|
||||||
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType>
|
|
||||||
struct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>> {
|
|
||||||
using Type = Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>;
|
|
||||||
using ValidType = void;
|
|
||||||
|
|
||||||
static Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape(const Type &f) {
|
|
||||||
return f.dimensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr bool
|
|
||||||
is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> & /*shape*/) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct helper {};
|
|
||||||
|
|
||||||
template <size_t... Is>
|
|
||||||
struct helper<index_sequence<Is...>> {
|
|
||||||
static constexpr auto value = concat(const_name(((void) Is, "?"))...);
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr auto dimensions_descriptor
|
|
||||||
= helper<decltype(make_index_sequence<Type::NumIndices>())>::value;
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
static Type *alloc(Args &&...args) {
|
|
||||||
return new Type(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free(Type *tensor) { delete tensor; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Scalar_, typename std::ptrdiff_t... Indices, int Options_, typename IndexType>
|
|
||||||
struct eigen_tensor_helper<
|
|
||||||
Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>> {
|
|
||||||
using Type = Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>;
|
|
||||||
using ValidType = void;
|
|
||||||
|
|
||||||
static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>
|
|
||||||
get_shape(const Type & /*f*/) {
|
|
||||||
return get_shape();
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape() {
|
|
||||||
return Eigen::DSizes<typename Type::Index, Type::NumIndices>(Indices...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> &shape) {
|
|
||||||
return get_shape() == shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto dimensions_descriptor = concat(const_name<Indices>()...);
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
static Type *alloc(Args &&...args) {
|
|
||||||
Eigen::aligned_allocator<Type> allocator;
|
|
||||||
return ::new (allocator.allocate(1)) Type(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free(Type *tensor) {
|
|
||||||
Eigen::aligned_allocator<Type> allocator;
|
|
||||||
tensor->~Type();
|
|
||||||
allocator.deallocate(tensor, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, bool ShowDetails, bool NeedsWriteable = false>
|
|
||||||
struct get_tensor_descriptor {
|
|
||||||
static constexpr auto details
|
|
||||||
= const_name<NeedsWriteable>(", flags.writeable", "")
|
|
||||||
+ const_name<static_cast<int>(Type::Layout) == static_cast<int>(Eigen::RowMajor)>(
|
|
||||||
", flags.c_contiguous", ", flags.f_contiguous");
|
|
||||||
static constexpr auto value
|
|
||||||
= const_name("numpy.ndarray[") + npy_format_descriptor<typename Type::Scalar>::name
|
|
||||||
+ const_name("[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor
|
|
||||||
+ const_name("]") + const_name<ShowDetails>(details, const_name("")) + const_name("]");
|
|
||||||
};
|
|
||||||
|
|
||||||
// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member
|
|
||||||
// function. Falling back to a simple loop works around this issue.
|
|
||||||
//
|
|
||||||
// We need to disable the type-limits warning for the inner loop when size = 0.
|
|
||||||
|
|
||||||
PYBIND11_WARNING_PUSH
|
|
||||||
PYBIND11_WARNING_DISABLE_GCC("-Wtype-limits")
|
|
||||||
|
|
||||||
template <typename T, int size>
|
|
||||||
std::vector<T> convert_dsizes_to_vector(const Eigen::DSizes<T, size> &arr) {
|
|
||||||
std::vector<T> result(size);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
result[i] = arr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, int size>
|
|
||||||
Eigen::DSizes<T, size> get_shape_for_array(const array &arr) {
|
|
||||||
Eigen::DSizes<T, size> result;
|
|
||||||
const T *shape = arr.shape();
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
result[i] = shape[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_WARNING_POP
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
|
|
||||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
using Helper = eigen_tensor_helper<Type>;
|
|
||||||
static constexpr auto temp_name = get_tensor_descriptor<Type, false>::value;
|
|
||||||
PYBIND11_TYPE_CASTER(Type, temp_name);
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!convert) {
|
|
||||||
if (!isinstance<array>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
array temp = array::ensure(src);
|
|
||||||
if (!temp) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!temp.dtype().is(dtype::of<typename Type::Scalar>())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()> arr(
|
|
||||||
reinterpret_borrow<object>(src));
|
|
||||||
|
|
||||||
if (arr.ndim() != Type::NumIndices) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
|
|
||||||
|
|
||||||
if (!Helper::is_correct_shape(shape)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
|
|
||||||
auto data_pointer = arr.data();
|
|
||||||
#else
|
|
||||||
// Handle Eigen bug
|
|
||||||
auto data_pointer = const_cast<typename Type::Scalar *>(arr.data());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (is_tensor_aligned(arr.data())) {
|
|
||||||
value = Eigen::TensorMap<const Type, Eigen::Aligned>(data_pointer, shape);
|
|
||||||
} else {
|
|
||||||
value = Eigen::TensorMap<const Type>(data_pointer, shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(Type &&src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::reference
|
|
||||||
|| policy == return_value_policy::reference_internal) {
|
|
||||||
pybind11_fail("Cannot use a reference return value policy for an rvalue");
|
|
||||||
}
|
|
||||||
return cast_impl(&src, return_value_policy::move, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const Type &&src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::reference
|
|
||||||
|| policy == return_value_policy::reference_internal) {
|
|
||||||
pybind11_fail("Cannot use a reference return value policy for an rvalue");
|
|
||||||
}
|
|
||||||
return cast_impl(&src, return_value_policy::move, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(Type &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast_impl(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const Type &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(Type *src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic) {
|
|
||||||
policy = return_value_policy::take_ownership;
|
|
||||||
} else if (policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::reference;
|
|
||||||
}
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const Type *src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic) {
|
|
||||||
policy = return_value_policy::take_ownership;
|
|
||||||
} else if (policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::reference;
|
|
||||||
}
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
static handle cast_impl(C *src, return_value_policy policy, handle parent) {
|
|
||||||
object parent_object;
|
|
||||||
bool writeable = false;
|
|
||||||
switch (policy) {
|
|
||||||
case return_value_policy::move:
|
|
||||||
if (std::is_const<C>::value) {
|
|
||||||
pybind11_fail("Cannot move from a constant reference");
|
|
||||||
}
|
|
||||||
|
|
||||||
src = Helper::alloc(std::move(*src));
|
|
||||||
|
|
||||||
parent_object
|
|
||||||
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
|
|
||||||
writeable = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::take_ownership:
|
|
||||||
if (std::is_const<C>::value) {
|
|
||||||
// This cast is ugly, and might be UB in some cases, but we don't have an
|
|
||||||
// alternative here as we must free that memory
|
|
||||||
Helper::free(const_cast<Type *>(src));
|
|
||||||
pybind11_fail("Cannot take ownership of a const reference");
|
|
||||||
}
|
|
||||||
|
|
||||||
parent_object
|
|
||||||
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
|
|
||||||
writeable = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::copy:
|
|
||||||
writeable = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::reference:
|
|
||||||
parent_object = none();
|
|
||||||
writeable = !std::is_const<C>::value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::reference_internal:
|
|
||||||
// Default should do the right thing
|
|
||||||
if (!parent) {
|
|
||||||
pybind11_fail("Cannot use reference internal when there is no parent");
|
|
||||||
}
|
|
||||||
parent_object = reinterpret_borrow<object>(parent);
|
|
||||||
writeable = !std::is_const<C>::value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pybind11_fail("pybind11 bug in eigen.h, please file a bug report");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
|
|
||||||
convert_dsizes_to_vector(Helper::get_shape(*src)), src->data(), parent_object);
|
|
||||||
|
|
||||||
if (!writeable) {
|
|
||||||
array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename StoragePointerType,
|
|
||||||
bool needs_writeable,
|
|
||||||
enable_if_t<!needs_writeable, bool> = true>
|
|
||||||
StoragePointerType get_array_data_for_type(array &arr) {
|
|
||||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
|
|
||||||
return reinterpret_cast<StoragePointerType>(arr.data());
|
|
||||||
#else
|
|
||||||
// Handle Eigen bug
|
|
||||||
return reinterpret_cast<StoragePointerType>(const_cast<void *>(arr.data()));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename StoragePointerType,
|
|
||||||
bool needs_writeable,
|
|
||||||
enable_if_t<needs_writeable, bool> = true>
|
|
||||||
StoragePointerType get_array_data_for_type(array &arr) {
|
|
||||||
return reinterpret_cast<StoragePointerType>(arr.mutable_data());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = void>
|
|
||||||
struct get_storage_pointer_type;
|
|
||||||
|
|
||||||
template <typename MapType>
|
|
||||||
struct get_storage_pointer_type<MapType, void_t<typename MapType::StoragePointerType>> {
|
|
||||||
using SPT = typename MapType::StoragePointerType;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename MapType>
|
|
||||||
struct get_storage_pointer_type<MapType, void_t<typename MapType::PointerArgType>> {
|
|
||||||
using SPT = typename MapType::PointerArgType;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, int Options>
|
|
||||||
struct type_caster<Eigen::TensorMap<Type, Options>,
|
|
||||||
typename eigen_tensor_helper<remove_cv_t<Type>>::ValidType> {
|
|
||||||
static_assert(!std::is_pointer<typename Type::Scalar>::value,
|
|
||||||
PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);
|
|
||||||
using MapType = Eigen::TensorMap<Type, Options>;
|
|
||||||
using Helper = eigen_tensor_helper<remove_cv_t<Type>>;
|
|
||||||
|
|
||||||
bool load(handle src, bool /*convert*/) {
|
|
||||||
// Note that we have a lot more checks here as we want to make sure to avoid copies
|
|
||||||
if (!isinstance<array>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto arr = reinterpret_borrow<array>(src);
|
|
||||||
if ((arr.flags() & compute_array_flag_from_tensor<Type>()) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!arr.dtype().is(dtype::of<typename Type::Scalar>())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arr.ndim() != Type::NumIndices) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is_aligned = (Options & Eigen::Aligned) != 0;
|
|
||||||
|
|
||||||
if (is_aligned && !is_tensor_aligned(arr.data())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);
|
|
||||||
|
|
||||||
if (!Helper::is_correct_shape(shape)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needs_writeable && !arr.writeable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = get_array_data_for_type<typename get_storage_pointer_type<MapType>::SPT,
|
|
||||||
needs_writeable>(arr);
|
|
||||||
|
|
||||||
value.reset(new MapType(std::move(result), std::move(shape)));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(MapType &&src, return_value_policy policy, handle parent) {
|
|
||||||
return cast_impl(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const MapType &&src, return_value_policy policy, handle parent) {
|
|
||||||
return cast_impl(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(MapType &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast_impl(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const MapType &src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::copy;
|
|
||||||
}
|
|
||||||
return cast(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(MapType *src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic) {
|
|
||||||
policy = return_value_policy::take_ownership;
|
|
||||||
} else if (policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::reference;
|
|
||||||
}
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const MapType *src, return_value_policy policy, handle parent) {
|
|
||||||
if (policy == return_value_policy::automatic) {
|
|
||||||
policy = return_value_policy::take_ownership;
|
|
||||||
} else if (policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = return_value_policy::reference;
|
|
||||||
}
|
|
||||||
return cast_impl(src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
static handle cast_impl(C *src, return_value_policy policy, handle parent) {
|
|
||||||
object parent_object;
|
|
||||||
constexpr bool writeable = !std::is_const<C>::value;
|
|
||||||
switch (policy) {
|
|
||||||
case return_value_policy::reference:
|
|
||||||
parent_object = none();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::reference_internal:
|
|
||||||
// Default should do the right thing
|
|
||||||
if (!parent) {
|
|
||||||
pybind11_fail("Cannot use reference internal when there is no parent");
|
|
||||||
}
|
|
||||||
parent_object = reinterpret_borrow<object>(parent);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case return_value_policy::take_ownership:
|
|
||||||
delete src;
|
|
||||||
// fallthrough
|
|
||||||
default:
|
|
||||||
// move, take_ownership don't make any sense for a ref/map:
|
|
||||||
pybind11_fail("Invalid return_value_policy for Eigen Map type, must be either "
|
|
||||||
"reference or reference_internal");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(
|
|
||||||
convert_dsizes_to_vector(Helper::get_shape(*src)),
|
|
||||||
src->data(),
|
|
||||||
std::move(parent_object));
|
|
||||||
|
|
||||||
if (!writeable) {
|
|
||||||
array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
|
|
||||||
|
|
||||||
static constexpr bool needs_writeable = !std::is_const<typename std::remove_pointer<
|
|
||||||
typename get_storage_pointer_type<MapType>::SPT>::type>::value;
|
|
||||||
#else
|
|
||||||
// Handle Eigen bug
|
|
||||||
static constexpr bool needs_writeable = !std::is_const<Type>::value;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// TODO: Move to std::optional once std::optional has more support
|
|
||||||
std::unique_ptr<MapType> value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr auto name = get_tensor_descriptor<Type, true, needs_writeable>::value;
|
|
||||||
explicit operator MapType *() { return value.get(); }
|
|
||||||
explicit operator MapType &() { return *value; }
|
|
||||||
explicit operator MapType &&() && { return std::move(*value); }
|
|
||||||
|
|
||||||
template <typename T_>
|
|
||||||
using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
316
3rdparty/pybind11/include/pybind11/embed.h
vendored
316
3rdparty/pybind11/include/pybind11/embed.h
vendored
@ -1,316 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/embed.h: Support for embedding the interpreter
|
|
||||||
|
|
||||||
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
#include "eval.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
# error Embedding the interpreter is not supported with PyPy
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
|
||||||
extern "C" PyObject *pybind11_init_impl_##name(); \
|
|
||||||
extern "C" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
Add a new module to the table of builtins for the interpreter. Must be
|
|
||||||
defined in global scope. The first macro parameter is the name of the
|
|
||||||
module (without quotes). The second parameter is the variable which will
|
|
||||||
be used as the interface to add functions and classes to the module.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
PYBIND11_EMBEDDED_MODULE(example, m) {
|
|
||||||
// ... initialize functions and classes here
|
|
||||||
m.def("foo", []() {
|
|
||||||
return "Hello, World!";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
\endrst */
|
|
||||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
|
||||||
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
|
|
||||||
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
|
|
||||||
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
|
||||||
auto m = ::pybind11::module_::create_extension_module( \
|
|
||||||
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
|
|
||||||
try { \
|
|
||||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
|
||||||
return m.ptr(); \
|
|
||||||
} \
|
|
||||||
PYBIND11_CATCH_INIT_EXCEPTIONS \
|
|
||||||
} \
|
|
||||||
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
|
||||||
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
|
|
||||||
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
|
||||||
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
|
|
||||||
& variable) // NOLINT(bugprone-macro-parentheses)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
|
||||||
struct embedded_module {
|
|
||||||
using init_t = PyObject *(*) ();
|
|
||||||
embedded_module(const char *name, init_t init) {
|
|
||||||
if (Py_IsInitialized() != 0) {
|
|
||||||
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = PyImport_AppendInittab(name, init);
|
|
||||||
if (result == -1) {
|
|
||||||
pybind11_fail("Insufficient memory to add a new module");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wide_char_arg_deleter {
|
|
||||||
void operator()(wchar_t *ptr) const {
|
|
||||||
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
|
|
||||||
PyMem_RawFree(ptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline wchar_t *widen_chars(const char *safe_arg) {
|
|
||||||
wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);
|
|
||||||
return widened_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void precheck_interpreter() {
|
|
||||||
if (Py_IsInitialized() != 0) {
|
|
||||||
pybind11_fail("The interpreter is already running");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)
|
|
||||||
# define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
|
|
||||||
inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
|
|
||||||
int argc,
|
|
||||||
const char *const *argv,
|
|
||||||
bool add_program_dir_to_path) {
|
|
||||||
detail::precheck_interpreter();
|
|
||||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
|
||||||
# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
|
|
||||||
PyEval_InitThreads();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Before it was special-cased in python 3.8, passing an empty or null argv
|
|
||||||
// caused a segfault, so we have to reimplement the special case ourselves.
|
|
||||||
bool special_case = (argv == nullptr || argc <= 0);
|
|
||||||
|
|
||||||
const char *const empty_argv[]{"\0"};
|
|
||||||
const char *const *safe_argv = special_case ? empty_argv : argv;
|
|
||||||
if (special_case) {
|
|
||||||
argc = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto argv_size = static_cast<size_t>(argc);
|
|
||||||
// SetArgv* on python 3 takes wchar_t, so we have to convert.
|
|
||||||
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
|
|
||||||
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
|
|
||||||
widened_argv_entries.reserve(argv_size);
|
|
||||||
for (size_t ii = 0; ii < argv_size; ++ii) {
|
|
||||||
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
|
|
||||||
if (!widened_argv_entries.back()) {
|
|
||||||
// A null here indicates a character-encoding failure or the python
|
|
||||||
// interpreter out of memory. Give up.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
widened_argv[ii] = widened_argv_entries.back().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *pysys_argv = widened_argv.get();
|
|
||||||
|
|
||||||
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
|
|
||||||
inline void initialize_interpreter(PyConfig *config,
|
|
||||||
int argc = 0,
|
|
||||||
const char *const *argv = nullptr,
|
|
||||||
bool add_program_dir_to_path = true) {
|
|
||||||
detail::precheck_interpreter();
|
|
||||||
PyStatus status = PyConfig_SetBytesArgv(config, argc, const_cast<char *const *>(argv));
|
|
||||||
if (PyStatus_Exception(status) != 0) {
|
|
||||||
// A failure here indicates a character-encoding failure or the python
|
|
||||||
// interpreter out of memory. Give up.
|
|
||||||
PyConfig_Clear(config);
|
|
||||||
throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
|
|
||||||
: "Failed to prepare CPython");
|
|
||||||
}
|
|
||||||
status = Py_InitializeFromConfig(config);
|
|
||||||
if (PyStatus_Exception(status) != 0) {
|
|
||||||
PyConfig_Clear(config);
|
|
||||||
throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg
|
|
||||||
: "Failed to init CPython");
|
|
||||||
}
|
|
||||||
if (add_program_dir_to_path) {
|
|
||||||
PyRun_SimpleString("import sys, os.path; "
|
|
||||||
"sys.path.insert(0, "
|
|
||||||
"os.path.abspath(os.path.dirname(sys.argv[0])) "
|
|
||||||
"if sys.argv and os.path.exists(sys.argv[0]) else '')");
|
|
||||||
}
|
|
||||||
PyConfig_Clear(config);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
|
||||||
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
|
||||||
optional `init_signal_handlers` parameter can be used to skip the registration of
|
|
||||||
signal handlers (see the `Python documentation`_ for details). Calling this function
|
|
||||||
again after the interpreter has already been initialized is a fatal error.
|
|
||||||
|
|
||||||
If initializing the Python interpreter fails, then the program is terminated. (This
|
|
||||||
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
|
|
||||||
of throwing exceptions on errors.)
|
|
||||||
|
|
||||||
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
|
|
||||||
used to populate ``sys.argv`` and ``sys.path``.
|
|
||||||
See the |PySys_SetArgvEx documentation|_ for details.
|
|
||||||
|
|
||||||
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
|
|
||||||
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
|
|
||||||
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
|
|
||||||
\endrst */
|
|
||||||
inline void initialize_interpreter(bool init_signal_handlers = true,
|
|
||||||
int argc = 0,
|
|
||||||
const char *const *argv = nullptr,
|
|
||||||
bool add_program_dir_to_path = true) {
|
|
||||||
#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
|
|
||||||
detail::initialize_interpreter_pre_pyconfig(
|
|
||||||
init_signal_handlers, argc, argv, add_program_dir_to_path);
|
|
||||||
#else
|
|
||||||
PyConfig config;
|
|
||||||
PyConfig_InitPythonConfig(&config);
|
|
||||||
// See PR #4473 for background
|
|
||||||
config.parse_argv = 0;
|
|
||||||
|
|
||||||
config.install_signal_handlers = init_signal_handlers ? 1 : 0;
|
|
||||||
initialize_interpreter(&config, argc, argv, add_program_dir_to_path);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
|
||||||
after this. In addition, pybind11 objects must not outlive the interpreter:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
{ // BAD
|
|
||||||
py::initialize_interpreter();
|
|
||||||
auto hello = py::str("Hello, World!");
|
|
||||||
py::finalize_interpreter();
|
|
||||||
} // <-- BOOM, hello's destructor is called after interpreter shutdown
|
|
||||||
|
|
||||||
{ // GOOD
|
|
||||||
py::initialize_interpreter();
|
|
||||||
{ // scoped
|
|
||||||
auto hello = py::str("Hello, World!");
|
|
||||||
} // <-- OK, hello is cleaned up properly
|
|
||||||
py::finalize_interpreter();
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // BETTER
|
|
||||||
py::scoped_interpreter guard{};
|
|
||||||
auto hello = py::str("Hello, World!");
|
|
||||||
}
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
The interpreter can be restarted by calling `initialize_interpreter` again.
|
|
||||||
Modules created using pybind11 can be safely re-initialized. However, Python
|
|
||||||
itself cannot completely unload binary extension modules and there are several
|
|
||||||
caveats with regard to interpreter restarting. All the details can be found
|
|
||||||
in the CPython documentation. In short, not all interpreter memory may be
|
|
||||||
freed, either due to reference cycles or user-created global data.
|
|
||||||
|
|
||||||
\endrst */
|
|
||||||
inline void finalize_interpreter() {
|
|
||||||
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
|
||||||
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
|
||||||
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
|
||||||
detail::internals **internals_ptr_ptr = detail::get_internals_pp();
|
|
||||||
// It could also be stashed in state_dict, so look there too:
|
|
||||||
if (object internals_obj
|
|
||||||
= get_internals_obj_from_state_dict(detail::get_python_state_dict())) {
|
|
||||||
internals_ptr_ptr = detail::get_internals_pp_from_capsule(internals_obj);
|
|
||||||
}
|
|
||||||
// Local internals contains data managed by the current interpreter, so we must clear them to
|
|
||||||
// avoid undefined behaviors when initializing another interpreter
|
|
||||||
detail::get_local_internals().registered_types_cpp.clear();
|
|
||||||
detail::get_local_internals().registered_exception_translators.clear();
|
|
||||||
|
|
||||||
Py_Finalize();
|
|
||||||
|
|
||||||
if (internals_ptr_ptr) {
|
|
||||||
delete *internals_ptr_ptr;
|
|
||||||
*internals_ptr_ptr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
|
||||||
This a move-only guard and only a single instance can exist.
|
|
||||||
|
|
||||||
See `initialize_interpreter` for a discussion of its constructor arguments.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
#include <pybind11/embed.h>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
py::scoped_interpreter guard{};
|
|
||||||
py::print(Hello, World!);
|
|
||||||
} // <-- interpreter shutdown
|
|
||||||
\endrst */
|
|
||||||
class scoped_interpreter {
|
|
||||||
public:
|
|
||||||
explicit scoped_interpreter(bool init_signal_handlers = true,
|
|
||||||
int argc = 0,
|
|
||||||
const char *const *argv = nullptr,
|
|
||||||
bool add_program_dir_to_path = true) {
|
|
||||||
initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX
|
|
||||||
explicit scoped_interpreter(PyConfig *config,
|
|
||||||
int argc = 0,
|
|
||||||
const char *const *argv = nullptr,
|
|
||||||
bool add_program_dir_to_path = true) {
|
|
||||||
initialize_interpreter(config, argc, argv, add_program_dir_to_path);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
scoped_interpreter(const scoped_interpreter &) = delete;
|
|
||||||
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
|
||||||
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
|
||||||
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
|
||||||
|
|
||||||
~scoped_interpreter() {
|
|
||||||
if (is_valid) {
|
|
||||||
finalize_interpreter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_valid = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
156
3rdparty/pybind11/include/pybind11/eval.h
vendored
156
3rdparty/pybind11/include/pybind11/eval.h
vendored
@ -1,156 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/eval.h: Support for evaluating Python expressions and statements
|
|
||||||
from strings and files
|
|
||||||
|
|
||||||
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
|
||||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
inline void ensure_builtins_in_globals(object &global) {
|
|
||||||
#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
|
|
||||||
// Running exec and eval adds `builtins` module under `__builtins__` key to
|
|
||||||
// globals if not yet present. Python 3.8 made PyRun_String behave
|
|
||||||
// similarly. Let's also do that for older versions, for consistency. This
|
|
||||||
// was missing from PyPy3.8 7.3.7.
|
|
||||||
if (!global.contains("__builtins__"))
|
|
||||||
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
|
|
||||||
#else
|
|
||||||
(void) global;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
enum eval_mode {
|
|
||||||
/// Evaluate a string containing an isolated expression
|
|
||||||
eval_expr,
|
|
||||||
|
|
||||||
/// Evaluate a string containing a single statement. Returns \c none
|
|
||||||
eval_single_statement,
|
|
||||||
|
|
||||||
/// Evaluate a string containing a sequence of statement. Returns \c none
|
|
||||||
eval_statements
|
|
||||||
};
|
|
||||||
|
|
||||||
template <eval_mode mode = eval_expr>
|
|
||||||
object eval(const str &expr, object global = globals(), object local = object()) {
|
|
||||||
if (!local) {
|
|
||||||
local = global;
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::ensure_builtins_in_globals(global);
|
|
||||||
|
|
||||||
/* PyRun_String does not accept a PyObject / encoding specifier,
|
|
||||||
this seems to be the only alternative */
|
|
||||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
switch (mode) {
|
|
||||||
case eval_expr:
|
|
||||||
start = Py_eval_input;
|
|
||||||
break;
|
|
||||||
case eval_single_statement:
|
|
||||||
start = Py_single_input;
|
|
||||||
break;
|
|
||||||
case eval_statements:
|
|
||||||
start = Py_file_input;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pybind11_fail("invalid evaluation mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
|
||||||
if (!result) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
return reinterpret_steal<object>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <eval_mode mode = eval_expr, size_t N>
|
|
||||||
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
|
||||||
/* Support raw string literals by removing common leading whitespace */
|
|
||||||
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
|
|
||||||
return eval<mode>(expr, std::move(global), std::move(local));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void exec(const str &expr, object global = globals(), object local = object()) {
|
|
||||||
eval<eval_statements>(expr, std::move(global), std::move(local));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N>
|
|
||||||
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
|
||||||
eval<eval_statements>(s, std::move(global), std::move(local));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
template <eval_mode mode = eval_statements>
|
|
||||||
object eval_file(str, object, object) {
|
|
||||||
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
|
||||||
}
|
|
||||||
template <eval_mode mode = eval_statements>
|
|
||||||
object eval_file(str, object) {
|
|
||||||
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
|
||||||
}
|
|
||||||
template <eval_mode mode = eval_statements>
|
|
||||||
object eval_file(str) {
|
|
||||||
pybind11_fail("eval_file not supported in PyPy3. Use eval");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template <eval_mode mode = eval_statements>
|
|
||||||
object eval_file(str fname, object global = globals(), object local = object()) {
|
|
||||||
if (!local) {
|
|
||||||
local = global;
|
|
||||||
}
|
|
||||||
|
|
||||||
detail::ensure_builtins_in_globals(global);
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
switch (mode) {
|
|
||||||
case eval_expr:
|
|
||||||
start = Py_eval_input;
|
|
||||||
break;
|
|
||||||
case eval_single_statement:
|
|
||||||
start = Py_single_input;
|
|
||||||
break;
|
|
||||||
case eval_statements:
|
|
||||||
start = Py_file_input;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pybind11_fail("invalid evaluation mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
int closeFile = 1;
|
|
||||||
std::string fname_str = (std::string) fname;
|
|
||||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
|
||||||
if (!f) {
|
|
||||||
PyErr_Clear();
|
|
||||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!global.contains("__file__")) {
|
|
||||||
global["__file__"] = std::move(fname);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *result
|
|
||||||
= PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
return reinterpret_steal<object>(result);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
137
3rdparty/pybind11/include/pybind11/functional.h
vendored
137
3rdparty/pybind11/include/pybind11/functional.h
vendored
@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/functional.h: std::function<> support
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <typename Return, typename... Args>
|
|
||||||
struct type_caster<std::function<Return(Args...)>> {
|
|
||||||
using type = std::function<Return(Args...)>;
|
|
||||||
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
|
||||||
using function_type = Return (*)(Args...);
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (src.is_none()) {
|
|
||||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
|
||||||
if (!convert) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isinstance<function>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto func = reinterpret_borrow<function>(src);
|
|
||||||
|
|
||||||
/*
|
|
||||||
When passing a C++ function as an argument to another C++
|
|
||||||
function via Python, every function call would normally involve
|
|
||||||
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
|
||||||
Here, we try to at least detect the case where the function is
|
|
||||||
stateless (i.e. function pointer or lambda function without
|
|
||||||
captured variables), in which case the roundtrip can be avoided.
|
|
||||||
*/
|
|
||||||
if (auto cfunc = func.cpp_function()) {
|
|
||||||
auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
|
|
||||||
if (cfunc_self == nullptr) {
|
|
||||||
PyErr_Clear();
|
|
||||||
} else if (isinstance<capsule>(cfunc_self)) {
|
|
||||||
auto c = reinterpret_borrow<capsule>(cfunc_self);
|
|
||||||
|
|
||||||
function_record *rec = nullptr;
|
|
||||||
// Check that we can safely reinterpret the capsule into a function_record
|
|
||||||
if (detail::is_function_record_capsule(c)) {
|
|
||||||
rec = c.get_pointer<function_record>();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (rec != nullptr) {
|
|
||||||
if (rec->is_stateless
|
|
||||||
&& same_type(typeid(function_type),
|
|
||||||
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
|
||||||
struct capture {
|
|
||||||
function_type f;
|
|
||||||
};
|
|
||||||
value = ((capture *) &rec->data)->f;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
rec = rec->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// PYPY segfaults here when passing builtin function like sum.
|
|
||||||
// Raising an fail exception here works to prevent the segfault, but only on gcc.
|
|
||||||
// See PR #1413 for full details
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure GIL is held during functor destruction
|
|
||||||
struct func_handle {
|
|
||||||
function f;
|
|
||||||
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
|
|
||||||
// This triggers a syntax error under very special conditions (very weird indeed).
|
|
||||||
explicit
|
|
||||||
#endif
|
|
||||||
func_handle(function &&f_) noexcept
|
|
||||||
: f(std::move(f_)) {
|
|
||||||
}
|
|
||||||
func_handle(const func_handle &f_) { operator=(f_); }
|
|
||||||
func_handle &operator=(const func_handle &f_) {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
f = f_.f;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~func_handle() {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
function kill_f(std::move(f));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// to emulate 'move initialization capture' in C++11
|
|
||||||
struct func_wrapper {
|
|
||||||
func_handle hfunc;
|
|
||||||
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
|
||||||
Return operator()(Args... args) const {
|
|
||||||
gil_scoped_acquire acq;
|
|
||||||
// casts the returned object as a rvalue to the return type
|
|
||||||
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
value = func_wrapper(func_handle(std::move(func)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Func>
|
|
||||||
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
|
||||||
if (!f_) {
|
|
||||||
return none().release();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = f_.template target<function_type>();
|
|
||||||
if (result) {
|
|
||||||
return cpp_function(*result, policy).release();
|
|
||||||
}
|
|
||||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type,
|
|
||||||
const_name("Callable[[") + concat(make_caster<Args>::name...)
|
|
||||||
+ const_name("], ") + make_caster<retval_type>::name
|
|
||||||
+ const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
239
3rdparty/pybind11/include/pybind11/gil.h
vendored
239
3rdparty/pybind11/include/pybind11/gil.h
vendored
@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/gil.h: RAII helpers for managing the GIL
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
|
|
||||||
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
|
||||||
# include "detail/internals.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// forward declarations
|
|
||||||
PyThreadState *get_thread_state_unchecked();
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
#if defined(WITH_THREAD)
|
|
||||||
|
|
||||||
# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
|
|
||||||
|
|
||||||
/* The functions below essentially reproduce the PyGILState_* API using a RAII
|
|
||||||
* pattern, but there are a few important differences:
|
|
||||||
*
|
|
||||||
* 1. When acquiring the GIL from an non-main thread during the finalization
|
|
||||||
* phase, the GILState API blindly terminates the calling thread, which
|
|
||||||
* is often not what is wanted. This API does not do this.
|
|
||||||
*
|
|
||||||
* 2. The gil_scoped_release function can optionally cut the relationship
|
|
||||||
* of a PyThreadState and its associated thread, which allows moving it to
|
|
||||||
* another thread (this is a fairly rare/advanced use case).
|
|
||||||
*
|
|
||||||
* 3. The reference count of an acquired thread state can be controlled. This
|
|
||||||
* can be handy to prevent cases where callbacks issued from an external
|
|
||||||
* thread would otherwise constantly construct and destroy thread state data
|
|
||||||
* structures.
|
|
||||||
*
|
|
||||||
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
|
|
||||||
* example which uses features 2 and 3 to migrate the Python thread of
|
|
||||||
* execution to another thread (to run the event loop on the original thread,
|
|
||||||
* in this case).
|
|
||||||
*/
|
|
||||||
|
|
||||||
class gil_scoped_acquire {
|
|
||||||
public:
|
|
||||||
PYBIND11_NOINLINE gil_scoped_acquire() {
|
|
||||||
auto &internals = detail::get_internals();
|
|
||||||
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
|
|
||||||
|
|
||||||
if (!tstate) {
|
|
||||||
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
|
|
||||||
calling from a Python thread). Since we use a different key, this ensures
|
|
||||||
we don't create a new thread state and deadlock in PyEval_AcquireThread
|
|
||||||
below. Note we don't save this state with internals.tstate, since we don't
|
|
||||||
create it we would fail to clear it (its reference count should be > 0). */
|
|
||||||
tstate = PyGILState_GetThisThreadState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tstate) {
|
|
||||||
tstate = PyThreadState_New(internals.istate);
|
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
||||||
if (!tstate) {
|
|
||||||
pybind11_fail("scoped_acquire: could not create thread state!");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
tstate->gilstate_counter = 0;
|
|
||||||
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
|
|
||||||
} else {
|
|
||||||
release = detail::get_thread_state_unchecked() != tstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (release) {
|
|
||||||
PyEval_AcquireThread(tstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
inc_ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
gil_scoped_acquire(const gil_scoped_acquire &) = delete;
|
|
||||||
gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
|
|
||||||
|
|
||||||
void inc_ref() { ++tstate->gilstate_counter; }
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE void dec_ref() {
|
|
||||||
--tstate->gilstate_counter;
|
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
||||||
if (detail::get_thread_state_unchecked() != tstate) {
|
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
|
|
||||||
}
|
|
||||||
if (tstate->gilstate_counter < 0) {
|
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
if (tstate->gilstate_counter == 0) {
|
|
||||||
# if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
|
|
||||||
if (!release) {
|
|
||||||
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
PyThreadState_Clear(tstate);
|
|
||||||
if (active) {
|
|
||||||
PyThreadState_DeleteCurrent();
|
|
||||||
}
|
|
||||||
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
|
|
||||||
release = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
|
||||||
/// GIL won't be acquired. This method should be used if the interpreter
|
|
||||||
/// could be shutting down when this is called, as thread deletion is not
|
|
||||||
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
|
||||||
/// protect subsequent code.
|
|
||||||
PYBIND11_NOINLINE void disarm() { active = false; }
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE ~gil_scoped_acquire() {
|
|
||||||
dec_ref();
|
|
||||||
if (release) {
|
|
||||||
PyEval_SaveThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyThreadState *tstate = nullptr;
|
|
||||||
bool release = true;
|
|
||||||
bool active = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
class gil_scoped_release {
|
|
||||||
public:
|
|
||||||
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
|
|
||||||
// `get_internals()` must be called here unconditionally in order to initialize
|
|
||||||
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
|
|
||||||
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
|
|
||||||
auto &internals = detail::get_internals();
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
|
|
||||||
tstate = PyEval_SaveThread();
|
|
||||||
if (disassoc) {
|
|
||||||
// Python >= 3.7 can remove this, it's an int before 3.7
|
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto)
|
|
||||||
auto key = internals.tstate;
|
|
||||||
PYBIND11_TLS_DELETE_VALUE(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gil_scoped_release(const gil_scoped_release &) = delete;
|
|
||||||
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
|
|
||||||
|
|
||||||
/// This method will disable the PyThreadState_DeleteCurrent call and the
|
|
||||||
/// GIL won't be acquired. This method should be used if the interpreter
|
|
||||||
/// could be shutting down when this is called, as thread deletion is not
|
|
||||||
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
|
|
||||||
/// protect subsequent code.
|
|
||||||
PYBIND11_NOINLINE void disarm() { active = false; }
|
|
||||||
|
|
||||||
~gil_scoped_release() {
|
|
||||||
if (!tstate) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
|
|
||||||
if (active) {
|
|
||||||
PyEval_RestoreThread(tstate);
|
|
||||||
}
|
|
||||||
if (disassoc) {
|
|
||||||
// Python >= 3.7 can remove this, it's an int before 3.7
|
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto)
|
|
||||||
auto key = detail::get_internals().tstate;
|
|
||||||
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyThreadState *tstate;
|
|
||||||
bool disassoc;
|
|
||||||
bool active = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# else // PYBIND11_SIMPLE_GIL_MANAGEMENT
|
|
||||||
|
|
||||||
class gil_scoped_acquire {
|
|
||||||
PyGILState_STATE state;
|
|
||||||
|
|
||||||
public:
|
|
||||||
gil_scoped_acquire() : state{PyGILState_Ensure()} {}
|
|
||||||
gil_scoped_acquire(const gil_scoped_acquire &) = delete;
|
|
||||||
gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
|
|
||||||
~gil_scoped_acquire() { PyGILState_Release(state); }
|
|
||||||
void disarm() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class gil_scoped_release {
|
|
||||||
PyThreadState *state;
|
|
||||||
|
|
||||||
public:
|
|
||||||
gil_scoped_release() : state{PyEval_SaveThread()} {}
|
|
||||||
gil_scoped_release(const gil_scoped_release &) = delete;
|
|
||||||
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
|
|
||||||
~gil_scoped_release() { PyEval_RestoreThread(state); }
|
|
||||||
void disarm() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
# endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
|
|
||||||
|
|
||||||
#else // WITH_THREAD
|
|
||||||
|
|
||||||
class gil_scoped_acquire {
|
|
||||||
public:
|
|
||||||
gil_scoped_acquire() {
|
|
||||||
// Trick to suppress `unused variable` error messages (at call sites).
|
|
||||||
(void) (this != (this + 1));
|
|
||||||
}
|
|
||||||
gil_scoped_acquire(const gil_scoped_acquire &) = delete;
|
|
||||||
gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
|
|
||||||
void disarm() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class gil_scoped_release {
|
|
||||||
public:
|
|
||||||
gil_scoped_release() {
|
|
||||||
// Trick to suppress `unused variable` error messages (at call sites).
|
|
||||||
(void) (this != (this + 1));
|
|
||||||
}
|
|
||||||
gil_scoped_release(const gil_scoped_release &) = delete;
|
|
||||||
gil_scoped_release &operator=(const gil_scoped_release &) = delete;
|
|
||||||
void disarm() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WITH_THREAD
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
265
3rdparty/pybind11/include/pybind11/iostream.h
vendored
265
3rdparty/pybind11/include/pybind11/iostream.h
vendored
@ -1,265 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python
|
|
||||||
|
|
||||||
Copyright (c) 2017 Henry F. Schreiner
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
WARNING: The implementation in this file is NOT thread safe. Multiple
|
|
||||||
threads writing to a redirected ostream concurrently cause data races
|
|
||||||
and potentially buffer overflows. Therefore it is currently a requirement
|
|
||||||
that all (possibly) concurrent redirected ostream writes are protected by
|
|
||||||
a mutex.
|
|
||||||
#HelpAppreciated: Work on iostream.h thread safety.
|
|
||||||
For more background see the discussions under
|
|
||||||
https://github.com/pybind/pybind11/pull/2982 and
|
|
||||||
https://github.com/pybind/pybind11/pull/2995.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
#include <streambuf>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// Buffer that writes to Python instead of C++
|
|
||||||
class pythonbuf : public std::streambuf {
|
|
||||||
private:
|
|
||||||
using traits_type = std::streambuf::traits_type;
|
|
||||||
|
|
||||||
const size_t buf_size;
|
|
||||||
std::unique_ptr<char[]> d_buffer;
|
|
||||||
object pywrite;
|
|
||||||
object pyflush;
|
|
||||||
|
|
||||||
int overflow(int c) override {
|
|
||||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
|
||||||
*pptr() = traits_type::to_char_type(c);
|
|
||||||
pbump(1);
|
|
||||||
}
|
|
||||||
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Computes how many bytes at the end of the buffer are part of an
|
|
||||||
// incomplete sequence of UTF-8 bytes.
|
|
||||||
// Precondition: pbase() < pptr()
|
|
||||||
size_t utf8_remainder() const {
|
|
||||||
const auto rbase = std::reverse_iterator<char *>(pbase());
|
|
||||||
const auto rpptr = std::reverse_iterator<char *>(pptr());
|
|
||||||
auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };
|
|
||||||
auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };
|
|
||||||
auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };
|
|
||||||
auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };
|
|
||||||
// If the last character is ASCII, there are no incomplete code points
|
|
||||||
if (is_ascii(*rpptr)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Otherwise, work back from the end of the buffer and find the first
|
|
||||||
// UTF-8 leading byte
|
|
||||||
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
|
|
||||||
const auto leading = std::find_if(rpptr, rpend, is_leading);
|
|
||||||
if (leading == rbase) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const auto dist = static_cast<size_t>(leading - rpptr);
|
|
||||||
size_t remainder = 0;
|
|
||||||
|
|
||||||
if (dist == 0) {
|
|
||||||
remainder = 1; // 1-byte code point is impossible
|
|
||||||
} else if (dist == 1) {
|
|
||||||
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
|
|
||||||
} else if (dist == 2) {
|
|
||||||
remainder = is_leading_3b(*leading) ? 0 : dist + 1;
|
|
||||||
}
|
|
||||||
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
|
|
||||||
// leading byte, either no remainder or invalid UTF-8.
|
|
||||||
// Invalid UTF-8 will cause an exception later when converting
|
|
||||||
// to a Python string, so that's not handled here.
|
|
||||||
return remainder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function must be non-virtual to be called in a destructor.
|
|
||||||
int _sync() {
|
|
||||||
if (pbase() != pptr()) { // If buffer is not empty
|
|
||||||
gil_scoped_acquire tmp;
|
|
||||||
// This subtraction cannot be negative, so dropping the sign.
|
|
||||||
auto size = static_cast<size_t>(pptr() - pbase());
|
|
||||||
size_t remainder = utf8_remainder();
|
|
||||||
|
|
||||||
if (size > remainder) {
|
|
||||||
str line(pbase(), size - remainder);
|
|
||||||
pywrite(std::move(line));
|
|
||||||
pyflush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the remainder at the end of the buffer to the beginning:
|
|
||||||
if (remainder > 0) {
|
|
||||||
std::memmove(pbase(), pptr() - remainder, remainder);
|
|
||||||
}
|
|
||||||
setp(pbase(), epptr());
|
|
||||||
pbump(static_cast<int>(remainder));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sync() override { return _sync(); }
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)
|
|
||||||
: buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr("write")),
|
|
||||||
pyflush(pyostream.attr("flush")) {
|
|
||||||
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pythonbuf(pythonbuf &&) = default;
|
|
||||||
|
|
||||||
/// Sync before destroy
|
|
||||||
~pythonbuf() override { _sync(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
This a move-only guard that redirects output.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
#include <pybind11/iostream.h>
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
{
|
|
||||||
py::scoped_ostream_redirect output;
|
|
||||||
std::cout << "Hello, World!"; // Python stdout
|
|
||||||
} // <-- return std::cout to normal
|
|
||||||
|
|
||||||
You can explicitly pass the c++ stream and the python object,
|
|
||||||
for example to guard stderr instead.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
{
|
|
||||||
py::scoped_ostream_redirect output{
|
|
||||||
std::cerr, py::module::import("sys").attr("stderr")};
|
|
||||||
std::cout << "Hello, World!";
|
|
||||||
}
|
|
||||||
\endrst */
|
|
||||||
class scoped_ostream_redirect {
|
|
||||||
protected:
|
|
||||||
std::streambuf *old;
|
|
||||||
std::ostream &costream;
|
|
||||||
detail::pythonbuf buffer;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit scoped_ostream_redirect(std::ostream &costream = std::cout,
|
|
||||||
const object &pyostream
|
|
||||||
= module_::import("sys").attr("stdout"))
|
|
||||||
: costream(costream), buffer(pyostream) {
|
|
||||||
old = costream.rdbuf(&buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
~scoped_ostream_redirect() { costream.rdbuf(old); }
|
|
||||||
|
|
||||||
scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
|
|
||||||
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
|
|
||||||
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
|
|
||||||
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
Like `scoped_ostream_redirect`, but redirects cerr by default. This class
|
|
||||||
is provided primary to make ``py::call_guard`` easier to make.
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
m.def("noisy_func", &noisy_func,
|
|
||||||
py::call_guard<scoped_ostream_redirect,
|
|
||||||
scoped_estream_redirect>());
|
|
||||||
|
|
||||||
\endrst */
|
|
||||||
class scoped_estream_redirect : public scoped_ostream_redirect {
|
|
||||||
public:
|
|
||||||
explicit scoped_estream_redirect(std::ostream &costream = std::cerr,
|
|
||||||
const object &pyostream
|
|
||||||
= module_::import("sys").attr("stderr"))
|
|
||||||
: scoped_ostream_redirect(costream, pyostream) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
// Class to redirect output as a context manager. C++ backend.
|
|
||||||
class OstreamRedirect {
|
|
||||||
bool do_stdout_;
|
|
||||||
bool do_stderr_;
|
|
||||||
std::unique_ptr<scoped_ostream_redirect> redirect_stdout;
|
|
||||||
std::unique_ptr<scoped_estream_redirect> redirect_stderr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit OstreamRedirect(bool do_stdout = true, bool do_stderr = true)
|
|
||||||
: do_stdout_(do_stdout), do_stderr_(do_stderr) {}
|
|
||||||
|
|
||||||
void enter() {
|
|
||||||
if (do_stdout_) {
|
|
||||||
redirect_stdout.reset(new scoped_ostream_redirect());
|
|
||||||
}
|
|
||||||
if (do_stderr_) {
|
|
||||||
redirect_stderr.reset(new scoped_estream_redirect());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void exit() {
|
|
||||||
redirect_stdout.reset();
|
|
||||||
redirect_stderr.reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
/** \rst
|
|
||||||
This is a helper function to add a C++ redirect context manager to Python
|
|
||||||
instead of using a C++ guard. To use it, add the following to your binding code:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
|
|
||||||
#include <pybind11/iostream.h>
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
py::add_ostream_redirect(m, "ostream_redirect");
|
|
||||||
|
|
||||||
You now have a Python context manager that redirects your output:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with m.ostream_redirect():
|
|
||||||
m.print_to_cout_function()
|
|
||||||
|
|
||||||
This manager can optionally be told which streams to operate on:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with m.ostream_redirect(stdout=true, stderr=true):
|
|
||||||
m.noisy_function_with_error_printing()
|
|
||||||
|
|
||||||
\endrst */
|
|
||||||
inline class_<detail::OstreamRedirect>
|
|
||||||
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
|
|
||||||
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
|
|
||||||
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
|
|
||||||
.def("__enter__", &detail::OstreamRedirect::enter)
|
|
||||||
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
1998
3rdparty/pybind11/include/pybind11/numpy.h
vendored
1998
3rdparty/pybind11/include/pybind11/numpy.h
vendored
File diff suppressed because it is too large
Load Diff
202
3rdparty/pybind11/include/pybind11/operators.h
vendored
202
3rdparty/pybind11/include/pybind11/operators.h
vendored
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/operator.h: Metatemplates for operator overloading
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/// Enumeration with all supported operator types
|
|
||||||
enum op_id : int {
|
|
||||||
op_add,
|
|
||||||
op_sub,
|
|
||||||
op_mul,
|
|
||||||
op_div,
|
|
||||||
op_mod,
|
|
||||||
op_divmod,
|
|
||||||
op_pow,
|
|
||||||
op_lshift,
|
|
||||||
op_rshift,
|
|
||||||
op_and,
|
|
||||||
op_xor,
|
|
||||||
op_or,
|
|
||||||
op_neg,
|
|
||||||
op_pos,
|
|
||||||
op_abs,
|
|
||||||
op_invert,
|
|
||||||
op_int,
|
|
||||||
op_long,
|
|
||||||
op_float,
|
|
||||||
op_str,
|
|
||||||
op_cmp,
|
|
||||||
op_gt,
|
|
||||||
op_ge,
|
|
||||||
op_lt,
|
|
||||||
op_le,
|
|
||||||
op_eq,
|
|
||||||
op_ne,
|
|
||||||
op_iadd,
|
|
||||||
op_isub,
|
|
||||||
op_imul,
|
|
||||||
op_idiv,
|
|
||||||
op_imod,
|
|
||||||
op_ilshift,
|
|
||||||
op_irshift,
|
|
||||||
op_iand,
|
|
||||||
op_ixor,
|
|
||||||
op_ior,
|
|
||||||
op_complex,
|
|
||||||
op_bool,
|
|
||||||
op_nonzero,
|
|
||||||
op_repr,
|
|
||||||
op_truediv,
|
|
||||||
op_itruediv,
|
|
||||||
op_hash
|
|
||||||
};
|
|
||||||
|
|
||||||
enum op_type : int {
|
|
||||||
op_l, /* base type on left */
|
|
||||||
op_r, /* base type on right */
|
|
||||||
op_u /* unary operator */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct self_t {};
|
|
||||||
static const self_t self = self_t();
|
|
||||||
|
|
||||||
/// Type for an unused type slot
|
|
||||||
struct undefined_t {};
|
|
||||||
|
|
||||||
/// Don't warn about an unused variable
|
|
||||||
inline self_t __self() { return self; }
|
|
||||||
|
|
||||||
/// base template of operator implementations
|
|
||||||
template <op_id, op_type, typename B, typename L, typename R>
|
|
||||||
struct op_impl {};
|
|
||||||
|
|
||||||
/// Operator implementation generator
|
|
||||||
template <op_id id, op_type ot, typename L, typename R>
|
|
||||||
struct op_ {
|
|
||||||
static constexpr bool op_enable_if_hook = true;
|
|
||||||
template <typename Class, typename... Extra>
|
|
||||||
void execute(Class &cl, const Extra &...extra) const {
|
|
||||||
using Base = typename Class::type;
|
|
||||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
|
||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
|
||||||
cl.def(op::name(), &op::execute, is_operator(), extra...);
|
|
||||||
}
|
|
||||||
template <typename Class, typename... Extra>
|
|
||||||
void execute_cast(Class &cl, const Extra &...extra) const {
|
|
||||||
using Base = typename Class::type;
|
|
||||||
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
|
|
||||||
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
|
|
||||||
using op = op_impl<id, ot, Base, L_type, R_type>;
|
|
||||||
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
|
|
||||||
template <typename B, typename L, typename R> \
|
|
||||||
struct op_impl<op_##id, op_l, B, L, R> { \
|
|
||||||
static char const *name() { return "__" #id "__"; } \
|
|
||||||
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
|
|
||||||
static B execute_cast(const L &l, const R &r) { return B(expr); } \
|
|
||||||
}; \
|
|
||||||
template <typename B, typename L, typename R> \
|
|
||||||
struct op_impl<op_##id, op_r, B, L, R> { \
|
|
||||||
static char const *name() { return "__" #rid "__"; } \
|
|
||||||
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
|
|
||||||
static B execute_cast(const R &r, const L &l) { return B(expr); } \
|
|
||||||
}; \
|
|
||||||
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
|
|
||||||
return op_<op_##id, op_l, self_t, self_t>(); \
|
|
||||||
} \
|
|
||||||
template <typename T> \
|
|
||||||
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
|
||||||
return op_<op_##id, op_l, self_t, T>(); \
|
|
||||||
} \
|
|
||||||
template <typename T> \
|
|
||||||
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
|
|
||||||
return op_<op_##id, op_r, T, self_t>(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
|
|
||||||
template <typename B, typename L, typename R> \
|
|
||||||
struct op_impl<op_##id, op_l, B, L, R> { \
|
|
||||||
static char const *name() { return "__" #id "__"; } \
|
|
||||||
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
|
|
||||||
static B execute_cast(L &l, const R &r) { return B(expr); } \
|
|
||||||
}; \
|
|
||||||
template <typename T> \
|
|
||||||
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
|
|
||||||
return op_<op_##id, op_l, self_t, T>(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
|
|
||||||
template <typename B, typename L> \
|
|
||||||
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
|
|
||||||
static char const *name() { return "__" #id "__"; } \
|
|
||||||
static auto execute(const L &l) -> decltype(expr) { return expr; } \
|
|
||||||
static B execute_cast(const L &l) { return B(expr); } \
|
|
||||||
}; \
|
|
||||||
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
|
|
||||||
return op_<op_##id, op_u, self_t, undefined_t>(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
|
|
||||||
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
|
|
||||||
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
|
|
||||||
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
|
|
||||||
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
|
|
||||||
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
|
|
||||||
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
|
|
||||||
// WARNING: This usage of `abs` should only be done for existing STL overloads.
|
|
||||||
// Adding overloads directly in to the `std::` namespace is advised against:
|
|
||||||
// https://en.cppreference.com/w/cpp/language/extending_std
|
|
||||||
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
|
|
||||||
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
|
|
||||||
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
|
|
||||||
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
|
|
||||||
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
|
|
||||||
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
|
|
||||||
|
|
||||||
#undef PYBIND11_BINARY_OPERATOR
|
|
||||||
#undef PYBIND11_INPLACE_OPERATOR
|
|
||||||
#undef PYBIND11_UNARY_OPERATOR
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
using detail::self;
|
|
||||||
// Add named operators so that they are accessible via `py::`.
|
|
||||||
using detail::hash;
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
92
3rdparty/pybind11/include/pybind11/options.h
vendored
92
3rdparty/pybind11/include/pybind11/options.h
vendored
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/options.h: global settings that are configurable at runtime.
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
|
|
||||||
class options {
|
|
||||||
public:
|
|
||||||
// Default RAII constructor, which leaves settings as they currently are.
|
|
||||||
options() : previous_state(global_state()) {}
|
|
||||||
|
|
||||||
// Class is non-copyable.
|
|
||||||
options(const options &) = delete;
|
|
||||||
options &operator=(const options &) = delete;
|
|
||||||
|
|
||||||
// Destructor, which restores settings that were in effect before.
|
|
||||||
~options() { global_state() = previous_state; }
|
|
||||||
|
|
||||||
// Setter methods (affect the global state):
|
|
||||||
|
|
||||||
options &disable_user_defined_docstrings() & {
|
|
||||||
global_state().show_user_defined_docstrings = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
options &enable_user_defined_docstrings() & {
|
|
||||||
global_state().show_user_defined_docstrings = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
options &disable_function_signatures() & {
|
|
||||||
global_state().show_function_signatures = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
options &enable_function_signatures() & {
|
|
||||||
global_state().show_function_signatures = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
options &disable_enum_members_docstring() & {
|
|
||||||
global_state().show_enum_members_docstring = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
options &enable_enum_members_docstring() & {
|
|
||||||
global_state().show_enum_members_docstring = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getter methods (return the global state):
|
|
||||||
|
|
||||||
static bool show_user_defined_docstrings() {
|
|
||||||
return global_state().show_user_defined_docstrings;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
|
||||||
|
|
||||||
static bool show_enum_members_docstring() {
|
|
||||||
return global_state().show_enum_members_docstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This type is not meant to be allocated on the heap.
|
|
||||||
void *operator new(size_t) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct state {
|
|
||||||
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
|
||||||
bool show_function_signatures = true; //< Include auto-generated function signatures
|
|
||||||
// in docstrings.
|
|
||||||
bool show_enum_members_docstring = true; //< Include auto-generated member list in enum
|
|
||||||
// docstrings.
|
|
||||||
};
|
|
||||||
|
|
||||||
static state &global_state() {
|
|
||||||
static state instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
state previous_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
2890
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
2890
3rdparty/pybind11/include/pybind11/pybind11.h
vendored
File diff suppressed because it is too large
Load Diff
2557
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
2557
3rdparty/pybind11/include/pybind11/pytypes.h
vendored
File diff suppressed because it is too large
Load Diff
447
3rdparty/pybind11/include/pybind11/stl.h
vendored
447
3rdparty/pybind11/include/pybind11/stl.h
vendored
@ -1,447 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/stl.h: Transparent conversion for STL data types
|
|
||||||
|
|
||||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "pybind11.h"
|
|
||||||
#include "detail/common.h"
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <ostream>
|
|
||||||
#include <set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <valarray>
|
|
||||||
|
|
||||||
// See `detail/common.h` for implementation of these guards.
|
|
||||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
|
||||||
# include <optional>
|
|
||||||
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
|
|
||||||
# include <experimental/optional>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_VARIANT)
|
|
||||||
# include <variant>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
|
|
||||||
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
|
|
||||||
template <typename T, typename U>
|
|
||||||
using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
|
|
||||||
remove_reference_t<U> &,
|
|
||||||
remove_reference_t<U> &&>;
|
|
||||||
|
|
||||||
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
|
|
||||||
/// used for forwarding a container's elements.
|
|
||||||
template <typename T, typename U>
|
|
||||||
constexpr forwarded_type<T, U> forward_like(U &&u) {
|
|
||||||
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if a container has a STL style reserve method.
|
|
||||||
// This will only return true for a `reserve()` with a `void` return.
|
|
||||||
template <typename C>
|
|
||||||
using has_reserve_method = std::is_same<decltype(std::declval<C>().reserve(0)), void>;
|
|
||||||
|
|
||||||
template <typename Type, typename Key>
|
|
||||||
struct set_caster {
|
|
||||||
using type = Type;
|
|
||||||
using key_conv = make_caster<Key>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
|
||||||
void reserve_maybe(const anyset &s, Type *) {
|
|
||||||
value.reserve(s.size());
|
|
||||||
}
|
|
||||||
void reserve_maybe(const anyset &, void *) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!isinstance<anyset>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto s = reinterpret_borrow<anyset>(src);
|
|
||||||
value.clear();
|
|
||||||
reserve_maybe(s, &value);
|
|
||||||
for (auto entry : s) {
|
|
||||||
key_conv conv;
|
|
||||||
if (!conv.load(entry, convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value.insert(cast_op<Key &&>(std::move(conv)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
|
||||||
policy = return_value_policy_override<Key>::policy(policy);
|
|
||||||
}
|
|
||||||
pybind11::set s;
|
|
||||||
for (auto &&value : src) {
|
|
||||||
auto value_ = reinterpret_steal<object>(
|
|
||||||
key_conv::cast(detail::forward_like<T>(value), policy, parent));
|
|
||||||
if (!value_ || !s.add(std::move(value_))) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, typename Key, typename Value>
|
|
||||||
struct map_caster {
|
|
||||||
using key_conv = make_caster<Key>;
|
|
||||||
using value_conv = make_caster<Value>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
|
||||||
void reserve_maybe(const dict &d, Type *) {
|
|
||||||
value.reserve(d.size());
|
|
||||||
}
|
|
||||||
void reserve_maybe(const dict &, void *) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!isinstance<dict>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto d = reinterpret_borrow<dict>(src);
|
|
||||||
value.clear();
|
|
||||||
reserve_maybe(d, &value);
|
|
||||||
for (auto it : d) {
|
|
||||||
key_conv kconv;
|
|
||||||
value_conv vconv;
|
|
||||||
if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
|
||||||
dict d;
|
|
||||||
return_value_policy policy_key = policy;
|
|
||||||
return_value_policy policy_value = policy;
|
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
|
||||||
policy_key = return_value_policy_override<Key>::policy(policy_key);
|
|
||||||
policy_value = return_value_policy_override<Value>::policy(policy_value);
|
|
||||||
}
|
|
||||||
for (auto &&kv : src) {
|
|
||||||
auto key = reinterpret_steal<object>(
|
|
||||||
key_conv::cast(detail::forward_like<T>(kv.first), policy_key, parent));
|
|
||||||
auto value = reinterpret_steal<object>(
|
|
||||||
value_conv::cast(detail::forward_like<T>(kv.second), policy_value, parent));
|
|
||||||
if (!key || !value) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
d[std::move(key)] = std::move(value);
|
|
||||||
}
|
|
||||||
return d.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type,
|
|
||||||
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
|
|
||||||
+ const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, typename Value>
|
|
||||||
struct list_caster {
|
|
||||||
using value_conv = make_caster<Value>;
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto s = reinterpret_borrow<sequence>(src);
|
|
||||||
value.clear();
|
|
||||||
reserve_maybe(s, &value);
|
|
||||||
for (auto it : s) {
|
|
||||||
value_conv conv;
|
|
||||||
if (!conv.load(it, convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value.push_back(cast_op<Value &&>(std::move(conv)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>
|
|
||||||
void reserve_maybe(const sequence &s, Type *) {
|
|
||||||
value.reserve(s.size());
|
|
||||||
}
|
|
||||||
void reserve_maybe(const sequence &, void *) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename T>
|
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
|
||||||
policy = return_value_policy_override<Value>::policy(policy);
|
|
||||||
}
|
|
||||||
list l(src.size());
|
|
||||||
ssize_t index = 0;
|
|
||||||
for (auto &&value : src) {
|
|
||||||
auto value_ = reinterpret_steal<object>(
|
|
||||||
value_conv::cast(detail::forward_like<T>(value), policy, parent));
|
|
||||||
if (!value_) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
|
||||||
}
|
|
||||||
return l.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, typename Alloc>
|
|
||||||
struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};
|
|
||||||
|
|
||||||
template <typename Type, typename Alloc>
|
|
||||||
struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};
|
|
||||||
|
|
||||||
template <typename Type, typename Alloc>
|
|
||||||
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
|
|
||||||
|
|
||||||
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
|
|
||||||
struct array_caster {
|
|
||||||
using value_conv = make_caster<Value>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <bool R = Resizable>
|
|
||||||
bool require_size(enable_if_t<R, size_t> size) {
|
|
||||||
if (value.size() != size) {
|
|
||||||
value.resize(size);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
template <bool R = Resizable>
|
|
||||||
bool require_size(enable_if_t<!R, size_t> size) {
|
|
||||||
return size == Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!isinstance<sequence>(src)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto l = reinterpret_borrow<sequence>(src);
|
|
||||||
if (!require_size(l.size())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
size_t ctr = 0;
|
|
||||||
for (auto it : l) {
|
|
||||||
value_conv conv;
|
|
||||||
if (!conv.load(it, convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value[ctr++] = cast_op<Value &&>(std::move(conv));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
|
||||||
list l(src.size());
|
|
||||||
ssize_t index = 0;
|
|
||||||
for (auto &&value : src) {
|
|
||||||
auto value_ = reinterpret_steal<object>(
|
|
||||||
value_conv::cast(detail::forward_like<T>(value), policy, parent));
|
|
||||||
if (!value_) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
|
||||||
}
|
|
||||||
return l.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(ArrayType,
|
|
||||||
const_name<Resizable>(const_name(""), const_name("Annotated["))
|
|
||||||
+ const_name("List[") + value_conv::name + const_name("]")
|
|
||||||
+ const_name<Resizable>(const_name(""),
|
|
||||||
const_name(", FixedSize(")
|
|
||||||
+ const_name<Size>() + const_name(")]")));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type, size_t Size>
|
|
||||||
struct type_caster<std::array<Type, Size>>
|
|
||||||
: array_caster<std::array<Type, Size>, Type, false, Size> {};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};
|
|
||||||
|
|
||||||
template <typename Key, typename Compare, typename Alloc>
|
|
||||||
struct type_caster<std::set<Key, Compare, Alloc>>
|
|
||||||
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
|
|
||||||
|
|
||||||
template <typename Key, typename Hash, typename Equal, typename Alloc>
|
|
||||||
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
|
|
||||||
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
|
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Compare, typename Alloc>
|
|
||||||
struct type_caster<std::map<Key, Value, Compare, Alloc>>
|
|
||||||
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
|
|
||||||
|
|
||||||
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>
|
|
||||||
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
|
|
||||||
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};
|
|
||||||
|
|
||||||
// This type caster is intended to be used for std::optional and std::experimental::optional
|
|
||||||
template <typename Type, typename Value = typename Type::value_type>
|
|
||||||
struct optional_caster {
|
|
||||||
using value_conv = make_caster<Value>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
|
||||||
if (!src) {
|
|
||||||
return none().release();
|
|
||||||
}
|
|
||||||
if (!std::is_lvalue_reference<T>::value) {
|
|
||||||
policy = return_value_policy_override<Value>::policy(policy);
|
|
||||||
}
|
|
||||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
|
||||||
return value_conv::cast(*std::forward<T>(src), policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if (!src) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (src.is_none()) {
|
|
||||||
return true; // default-constructed value is already empty
|
|
||||||
}
|
|
||||||
value_conv inner_caster;
|
|
||||||
if (!inner_caster.load(src, convert)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value.emplace(cast_op<Value &&>(std::move(inner_caster)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(Type, const_name("Optional[") + value_conv::name + const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_OPTIONAL)
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<std::experimental::optional<T>>
|
|
||||||
: public optional_caster<std::experimental::optional<T>> {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type_caster<std::experimental::nullopt_t>
|
|
||||||
: public void_caster<std::experimental::nullopt_t> {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Visit a variant and cast any found type to Python
|
|
||||||
struct variant_caster_visitor {
|
|
||||||
return_value_policy policy;
|
|
||||||
handle parent;
|
|
||||||
|
|
||||||
using result_type = handle; // required by boost::variant in C++11
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
result_type operator()(T &&src) const {
|
|
||||||
return make_caster<T>::cast(std::forward<T>(src), policy, parent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar
|
|
||||||
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
|
|
||||||
/// automatically using argument-dependent lookup. Users can provide specializations for other
|
|
||||||
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
|
|
||||||
template <template <typename...> class Variant>
|
|
||||||
struct visit_helper {
|
|
||||||
template <typename... Args>
|
|
||||||
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
|
|
||||||
return visit(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Generic variant caster
|
|
||||||
template <typename Variant>
|
|
||||||
struct variant_caster;
|
|
||||||
|
|
||||||
template <template <typename...> class V, typename... Ts>
|
|
||||||
struct variant_caster<V<Ts...>> {
|
|
||||||
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
|
|
||||||
|
|
||||||
template <typename U, typename... Us>
|
|
||||||
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
|
|
||||||
auto caster = make_caster<U>();
|
|
||||||
if (caster.load(src, convert)) {
|
|
||||||
value = cast_op<U>(std::move(caster));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return load_alternative(src, convert, type_list<Us...>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool load_alternative(handle, bool, type_list<>) { return false; }
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
// Do a first pass without conversions to improve constructor resolution.
|
|
||||||
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
|
|
||||||
// slot of the variant. Without two-pass loading `double` would be filled
|
|
||||||
// because it appears first and a conversion is possible.
|
|
||||||
if (convert && load_alternative(src, false, type_list<Ts...>{})) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return load_alternative(src, convert, type_list<Ts...>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Variant>
|
|
||||||
static handle cast(Variant &&src, return_value_policy policy, handle parent) {
|
|
||||||
return visit_helper<V>::call(variant_caster_visitor{policy, parent},
|
|
||||||
std::forward<Variant>(src));
|
|
||||||
}
|
|
||||||
|
|
||||||
using Type = V<Ts...>;
|
|
||||||
PYBIND11_TYPE_CASTER(Type,
|
|
||||||
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
|
|
||||||
+ const_name("]"));
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_VARIANT)
|
|
||||||
template <typename... Ts>
|
|
||||||
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type_caster<std::monostate> : public void_caster<std::monostate> {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
|
|
||||||
#ifdef PYBIND11_HAS_STRING_VIEW
|
|
||||||
os << str(obj).cast<std::string_view>();
|
|
||||||
#else
|
|
||||||
os << (std::string) str(obj);
|
|
||||||
#endif
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
116
3rdparty/pybind11/include/pybind11/stl/filesystem.h
vendored
116
3rdparty/pybind11/include/pybind11/stl/filesystem.h
vendored
@ -1,116 +0,0 @@
|
|||||||
// Copyright (c) 2021 The Pybind Development Team.
|
|
||||||
// All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../pybind11.h"
|
|
||||||
#include "../detail/common.h"
|
|
||||||
#include "../detail/descr.h"
|
|
||||||
#include "../cast.h"
|
|
||||||
#include "../pytypes.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef __has_include
|
|
||||||
# if defined(PYBIND11_CPP17)
|
|
||||||
# if __has_include(<filesystem>) && \
|
|
||||||
PY_VERSION_HEX >= 0x03060000
|
|
||||||
# include <filesystem>
|
|
||||||
# define PYBIND11_HAS_FILESYSTEM 1
|
|
||||||
# elif __has_include(<experimental/filesystem>)
|
|
||||||
# include <experimental/filesystem>
|
|
||||||
# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \
|
|
||||||
&& !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
|
|
||||||
# error \
|
|
||||||
"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
|
||||||
template <typename T>
|
|
||||||
struct path_caster {
|
|
||||||
|
|
||||||
private:
|
|
||||||
static PyObject *unicode_from_fs_native(const std::string &w) {
|
|
||||||
# if !defined(PYPY_VERSION)
|
|
||||||
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
|
|
||||||
# else
|
|
||||||
// PyPy mistakenly declares the first parameter as non-const.
|
|
||||||
return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *unicode_from_fs_native(const std::wstring &w) {
|
|
||||||
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static handle cast(const T &path, return_value_policy, handle) {
|
|
||||||
if (auto py_str = unicode_from_fs_native(path.native())) {
|
|
||||||
return module_::import("pathlib")
|
|
||||||
.attr("Path")(reinterpret_steal<object>(py_str))
|
|
||||||
.release();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool load(handle handle, bool) {
|
|
||||||
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
|
|
||||||
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
|
|
||||||
// issue #3168) so we do it ourselves instead.
|
|
||||||
PyObject *buf = PyOS_FSPath(handle.ptr());
|
|
||||||
if (!buf) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PyObject *native = nullptr;
|
|
||||||
if constexpr (std::is_same_v<typename T::value_type, char>) {
|
|
||||||
if (PyUnicode_FSConverter(buf, &native) != 0) {
|
|
||||||
if (auto *c_str = PyBytes_AsString(native)) {
|
|
||||||
// AsString returns a pointer to the internal buffer, which
|
|
||||||
// must not be free'd.
|
|
||||||
value = c_str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
|
|
||||||
if (PyUnicode_FSDecoder(buf, &native) != 0) {
|
|
||||||
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
|
|
||||||
// AsWideCharString returns a new string that must be free'd.
|
|
||||||
value = c_str; // Copies the string.
|
|
||||||
PyMem_Free(c_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Py_XDECREF(native);
|
|
||||||
Py_DECREF(buf);
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
PyErr_Clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
|
||||||
|
|
||||||
#if defined(PYBIND11_HAS_FILESYSTEM)
|
|
||||||
template <>
|
|
||||||
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
|
|
||||||
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
|
|
||||||
template <>
|
|
||||||
struct type_caster<std::experimental::filesystem::path>
|
|
||||||
: public path_caster<std::experimental::filesystem::path> {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
851
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
851
3rdparty/pybind11/include/pybind11/stl_bind.h
vendored
@ -1,851 +0,0 @@
|
|||||||
/*
|
|
||||||
pybind11/std_bind.h: Binding generators for STL data types
|
|
||||||
|
|
||||||
Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
|
|
||||||
|
|
||||||
All rights reserved. Use of this source code is governed by a
|
|
||||||
BSD-style license that can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
#include "detail/type_caster_base.h"
|
|
||||||
#include "cast.h"
|
|
||||||
#include "operators.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <sstream>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/* SFINAE helper class used by 'is_comparable */
|
|
||||||
template <typename T>
|
|
||||||
struct container_traits {
|
|
||||||
template <typename T2>
|
|
||||||
static std::true_type
|
|
||||||
test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
|
|
||||||
template <typename T2>
|
|
||||||
static std::false_type test_comparable(...);
|
|
||||||
template <typename T2>
|
|
||||||
static std::true_type test_value(typename T2::value_type *);
|
|
||||||
template <typename T2>
|
|
||||||
static std::false_type test_value(...);
|
|
||||||
template <typename T2>
|
|
||||||
static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
|
|
||||||
template <typename T2>
|
|
||||||
static std::false_type test_pair(...);
|
|
||||||
|
|
||||||
static constexpr const bool is_comparable
|
|
||||||
= std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
|
|
||||||
static constexpr const bool is_pair
|
|
||||||
= std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
|
|
||||||
static constexpr const bool is_vector
|
|
||||||
= std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
|
|
||||||
static constexpr const bool is_element = !is_pair && !is_vector;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Default: is_comparable -> std::false_type */
|
|
||||||
template <typename T, typename SFINAE = void>
|
|
||||||
struct is_comparable : std::false_type {};
|
|
||||||
|
|
||||||
/* For non-map data structures, check whether operator== can be instantiated */
|
|
||||||
template <typename T>
|
|
||||||
struct is_comparable<
|
|
||||||
T,
|
|
||||||
enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
|
|
||||||
: std::true_type {};
|
|
||||||
|
|
||||||
/* For a vector/map data structure, recursively check the value type
|
|
||||||
(which is std::pair for maps) */
|
|
||||||
template <typename T>
|
|
||||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>>
|
|
||||||
: is_comparable<typename recursive_container_traits<T>::type_to_check_recursively> {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct is_comparable<recursive_bottom> : std::true_type {};
|
|
||||||
|
|
||||||
/* For pairs, recursively check the two data types */
|
|
||||||
template <typename T>
|
|
||||||
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
|
||||||
static constexpr const bool value = is_comparable<typename T::first_type>::value
|
|
||||||
&& is_comparable<typename T::second_type>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Fallback functions */
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void vector_if_copy_constructible(const Args &...) {}
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void vector_if_equal_operator(const Args &...) {}
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void vector_if_insertion_operator(const Args &...) {}
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void vector_modifiers(const Args &...) {}
|
|
||||||
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
|
|
||||||
cl.def(init<const Vector &>(), "Copy constructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
|
|
||||||
using T = typename Vector::value_type;
|
|
||||||
|
|
||||||
cl.def(self == self);
|
|
||||||
cl.def(self != self);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"count",
|
|
||||||
[](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
|
|
||||||
arg("x"),
|
|
||||||
"Return the number of times ``x`` appears in the list");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"remove",
|
|
||||||
[](Vector &v, const T &x) {
|
|
||||||
auto p = std::find(v.begin(), v.end(), x);
|
|
||||||
if (p != v.end()) {
|
|
||||||
v.erase(p);
|
|
||||||
} else {
|
|
||||||
throw value_error();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
arg("x"),
|
|
||||||
"Remove the first item from the list whose value is x. "
|
|
||||||
"It is an error if there is no such item.");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__contains__",
|
|
||||||
[](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
|
|
||||||
arg("x"),
|
|
||||||
"Return true the container contains ``x``");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vector modifiers -- requires a copyable vector_type:
|
|
||||||
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
|
|
||||||
// seems silly to allow deletion but not insertion, so include them here too.)
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
void vector_modifiers(
|
|
||||||
enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
|
|
||||||
using T = typename Vector::value_type;
|
|
||||||
using SizeType = typename Vector::size_type;
|
|
||||||
using DiffType = typename Vector::difference_type;
|
|
||||||
|
|
||||||
auto wrap_i = [](DiffType i, SizeType n) {
|
|
||||||
if (i < 0) {
|
|
||||||
i += n;
|
|
||||||
}
|
|
||||||
if (i < 0 || (SizeType) i >= n) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
};
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"append",
|
|
||||||
[](Vector &v, const T &value) { v.push_back(value); },
|
|
||||||
arg("x"),
|
|
||||||
"Add an item to the end of the list");
|
|
||||||
|
|
||||||
cl.def(init([](const iterable &it) {
|
|
||||||
auto v = std::unique_ptr<Vector>(new Vector());
|
|
||||||
v->reserve(len_hint(it));
|
|
||||||
for (handle h : it) {
|
|
||||||
v->push_back(h.cast<T>());
|
|
||||||
}
|
|
||||||
return v.release();
|
|
||||||
}));
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"extend",
|
|
||||||
[](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
|
|
||||||
arg("L"),
|
|
||||||
"Extend the list by appending all the items in the given list");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"extend",
|
|
||||||
[](Vector &v, const iterable &it) {
|
|
||||||
const size_t old_size = v.size();
|
|
||||||
v.reserve(old_size + len_hint(it));
|
|
||||||
try {
|
|
||||||
for (handle h : it) {
|
|
||||||
v.push_back(h.cast<T>());
|
|
||||||
}
|
|
||||||
} catch (const cast_error &) {
|
|
||||||
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
|
|
||||||
v.end());
|
|
||||||
try {
|
|
||||||
v.shrink_to_fit();
|
|
||||||
} catch (const std::exception &) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
arg("L"),
|
|
||||||
"Extend the list by appending all the items in the given list");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"insert",
|
|
||||||
[](Vector &v, DiffType i, const T &x) {
|
|
||||||
// Can't use wrap_i; i == v.size() is OK
|
|
||||||
if (i < 0) {
|
|
||||||
i += v.size();
|
|
||||||
}
|
|
||||||
if (i < 0 || (SizeType) i > v.size()) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
v.insert(v.begin() + i, x);
|
|
||||||
},
|
|
||||||
arg("i"),
|
|
||||||
arg("x"),
|
|
||||||
"Insert an item at a given position.");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"pop",
|
|
||||||
[](Vector &v) {
|
|
||||||
if (v.empty()) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
T t = std::move(v.back());
|
|
||||||
v.pop_back();
|
|
||||||
return t;
|
|
||||||
},
|
|
||||||
"Remove and return the last item");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"pop",
|
|
||||||
[wrap_i](Vector &v, DiffType i) {
|
|
||||||
i = wrap_i(i, v.size());
|
|
||||||
T t = std::move(v[(SizeType) i]);
|
|
||||||
v.erase(std::next(v.begin(), i));
|
|
||||||
return t;
|
|
||||||
},
|
|
||||||
arg("i"),
|
|
||||||
"Remove and return the item at index ``i``");
|
|
||||||
|
|
||||||
cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
|
|
||||||
i = wrap_i(i, v.size());
|
|
||||||
v[(SizeType) i] = t;
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Slicing protocol
|
|
||||||
cl.def(
|
|
||||||
"__getitem__",
|
|
||||||
[](const Vector &v, const slice &slice) -> Vector * {
|
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
|
||||||
|
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *seq = new Vector();
|
|
||||||
seq->reserve((size_t) slicelength);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < slicelength; ++i) {
|
|
||||||
seq->push_back(v[start]);
|
|
||||||
start += step;
|
|
||||||
}
|
|
||||||
return seq;
|
|
||||||
},
|
|
||||||
arg("s"),
|
|
||||||
"Retrieve list elements using a slice object");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__setitem__",
|
|
||||||
[](Vector &v, const slice &slice, const Vector &value) {
|
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slicelength != value.size()) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Left and right hand size of slice assignment have different sizes!");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < slicelength; ++i) {
|
|
||||||
v[start] = value[i];
|
|
||||||
start += step;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Assign list elements using a slice object");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__delitem__",
|
|
||||||
[wrap_i](Vector &v, DiffType i) {
|
|
||||||
i = wrap_i(i, v.size());
|
|
||||||
v.erase(v.begin() + i);
|
|
||||||
},
|
|
||||||
"Delete the list elements at index ``i``");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__delitem__",
|
|
||||||
[](Vector &v, const slice &slice) {
|
|
||||||
size_t start = 0, stop = 0, step = 0, slicelength = 0;
|
|
||||||
|
|
||||||
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step == 1 && false) {
|
|
||||||
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < slicelength; ++i) {
|
|
||||||
v.erase(v.begin() + DiffType(start));
|
|
||||||
start += step - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Delete list elements using a slice object");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
|
||||||
// we have to access by copying; otherwise we return by reference.
|
|
||||||
template <typename Vector>
|
|
||||||
using vector_needs_copy
|
|
||||||
= negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),
|
|
||||||
typename Vector::value_type &>>;
|
|
||||||
|
|
||||||
// The usual case: access and iterate by reference
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {
|
|
||||||
using T = typename Vector::value_type;
|
|
||||||
using SizeType = typename Vector::size_type;
|
|
||||||
using DiffType = typename Vector::difference_type;
|
|
||||||
using ItType = typename Vector::iterator;
|
|
||||||
|
|
||||||
auto wrap_i = [](DiffType i, SizeType n) {
|
|
||||||
if (i < 0) {
|
|
||||||
i += n;
|
|
||||||
}
|
|
||||||
if (i < 0 || (SizeType) i >= n) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
};
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__getitem__",
|
|
||||||
[wrap_i](Vector &v, DiffType i) -> T & {
|
|
||||||
i = wrap_i(i, v.size());
|
|
||||||
return v[(SizeType) i];
|
|
||||||
},
|
|
||||||
return_value_policy::reference_internal // ref + keepalive
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__iter__",
|
|
||||||
[](Vector &v) {
|
|
||||||
return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
|
|
||||||
v.begin(), v.end());
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {
|
|
||||||
using T = typename Vector::value_type;
|
|
||||||
using SizeType = typename Vector::size_type;
|
|
||||||
using DiffType = typename Vector::difference_type;
|
|
||||||
using ItType = typename Vector::iterator;
|
|
||||||
cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
|
|
||||||
if (i < 0) {
|
|
||||||
i += v.size();
|
|
||||||
if (i < 0) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto i_st = static_cast<SizeType>(i);
|
|
||||||
if (i_st >= v.size()) {
|
|
||||||
throw index_error();
|
|
||||||
}
|
|
||||||
return v[i_st];
|
|
||||||
});
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__iter__",
|
|
||||||
[](Vector &v) {
|
|
||||||
return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Vector, typename Class_>
|
|
||||||
auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
|
|
||||||
-> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
|
|
||||||
void()) {
|
|
||||||
using size_type = typename Vector::size_type;
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__repr__",
|
|
||||||
[name](Vector &v) {
|
|
||||||
std::ostringstream s;
|
|
||||||
s << name << '[';
|
|
||||||
for (size_type i = 0; i < v.size(); ++i) {
|
|
||||||
s << v[i];
|
|
||||||
if (i != v.size() - 1) {
|
|
||||||
s << ", ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s << ']';
|
|
||||||
return s.str();
|
|
||||||
},
|
|
||||||
"Return the canonical string representation of this list.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide the buffer interface for vectors if we have data() and we have a format for it
|
|
||||||
// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data()
|
|
||||||
// is insufficient, we need to check it returns an appropriate pointer
|
|
||||||
template <typename Vector, typename = void>
|
|
||||||
struct vector_has_data_and_format : std::false_type {};
|
|
||||||
template <typename Vector>
|
|
||||||
struct vector_has_data_and_format<
|
|
||||||
Vector,
|
|
||||||
enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(),
|
|
||||||
std::declval<Vector>().data()),
|
|
||||||
typename Vector::value_type *>::value>> : std::true_type {};
|
|
||||||
|
|
||||||
// [workaround(intel)] Separate function required here
|
|
||||||
// Workaround as the Intel compiler does not compile the enable_if_t part below
|
|
||||||
// (tested with icc (ICC) 2021.1 Beta 20200827)
|
|
||||||
template <typename... Args>
|
|
||||||
constexpr bool args_any_are_buffer() {
|
|
||||||
return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [workaround(intel)] Separate function required here
|
|
||||||
// [workaround(msvc)] Can't use constexpr bool in return type
|
|
||||||
|
|
||||||
// Add the buffer interface to a vector
|
|
||||||
template <typename Vector, typename Class_, typename... Args>
|
|
||||||
void vector_buffer_impl(Class_ &cl, std::true_type) {
|
|
||||||
using T = typename Vector::value_type;
|
|
||||||
|
|
||||||
static_assert(vector_has_data_and_format<Vector>::value,
|
|
||||||
"There is not an appropriate format descriptor for this vector");
|
|
||||||
|
|
||||||
// numpy.h declares this for arbitrary types, but it may raise an exception and crash hard
|
|
||||||
// at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
|
|
||||||
format_descriptor<T>::format();
|
|
||||||
|
|
||||||
cl.def_buffer([](Vector &v) -> buffer_info {
|
|
||||||
return buffer_info(v.data(),
|
|
||||||
static_cast<ssize_t>(sizeof(T)),
|
|
||||||
format_descriptor<T>::format(),
|
|
||||||
1,
|
|
||||||
{v.size()},
|
|
||||||
{sizeof(T)});
|
|
||||||
});
|
|
||||||
|
|
||||||
cl.def(init([](const buffer &buf) {
|
|
||||||
auto info = buf.request();
|
|
||||||
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {
|
|
||||||
throw type_error("Only valid 1D buffers can be copied to a vector");
|
|
||||||
}
|
|
||||||
if (!detail::compare_buffer_info<T>::compare(info)
|
|
||||||
|| (ssize_t) sizeof(T) != info.itemsize) {
|
|
||||||
throw type_error("Format mismatch (Python: " + info.format
|
|
||||||
+ " C++: " + format_descriptor<T>::format() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
T *p = static_cast<T *>(info.ptr);
|
|
||||||
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
|
||||||
T *end = p + info.shape[0] * step;
|
|
||||||
if (step == 1) {
|
|
||||||
return Vector(p, end);
|
|
||||||
}
|
|
||||||
Vector vec;
|
|
||||||
vec.reserve((size_t) info.shape[0]);
|
|
||||||
for (; p != end; p += step) {
|
|
||||||
vec.push_back(*p);
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Vector, typename Class_, typename... Args>
|
|
||||||
void vector_buffer_impl(Class_ &, std::false_type) {}
|
|
||||||
|
|
||||||
template <typename Vector, typename Class_, typename... Args>
|
|
||||||
void vector_buffer(Class_ &cl) {
|
|
||||||
vector_buffer_impl<Vector, Class_, Args...>(
|
|
||||||
cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
//
|
|
||||||
// std::vector
|
|
||||||
//
|
|
||||||
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
|
|
||||||
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
|
|
||||||
using Class_ = class_<Vector, holder_type>;
|
|
||||||
|
|
||||||
// If the value_type is unregistered (e.g. a converting type) or is itself registered
|
|
||||||
// module-local then make the vector binding module-local as well:
|
|
||||||
using vtype = typename Vector::value_type;
|
|
||||||
auto *vtype_info = detail::get_type_info(typeid(vtype));
|
|
||||||
bool local = !vtype_info || vtype_info->module_local;
|
|
||||||
|
|
||||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
|
||||||
|
|
||||||
// Declare the buffer interface if a buffer_protocol() is passed in
|
|
||||||
detail::vector_buffer<Vector, Class_, Args...>(cl);
|
|
||||||
|
|
||||||
cl.def(init<>());
|
|
||||||
|
|
||||||
// Register copy constructor (if possible)
|
|
||||||
detail::vector_if_copy_constructible<Vector, Class_>(cl);
|
|
||||||
|
|
||||||
// Register comparison-related operators and functions (if possible)
|
|
||||||
detail::vector_if_equal_operator<Vector, Class_>(cl);
|
|
||||||
|
|
||||||
// Register stream insertion operator (if possible)
|
|
||||||
detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
|
|
||||||
|
|
||||||
// Modifiers require copyable vector value type
|
|
||||||
detail::vector_modifiers<Vector, Class_>(cl);
|
|
||||||
|
|
||||||
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
|
|
||||||
detail::vector_accessor<Vector, Class_>(cl);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__bool__",
|
|
||||||
[](const Vector &v) -> bool { return !v.empty(); },
|
|
||||||
"Check whether the list is nonempty");
|
|
||||||
|
|
||||||
cl.def("__len__", &Vector::size);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// C++ style functions deprecated, leaving it here as an example
|
|
||||||
cl.def(init<size_type>());
|
|
||||||
|
|
||||||
cl.def("resize",
|
|
||||||
(void (Vector::*) (size_type count)) & Vector::resize,
|
|
||||||
"changes the number of elements stored");
|
|
||||||
|
|
||||||
cl.def("erase",
|
|
||||||
[](Vector &v, SizeType i) {
|
|
||||||
if (i >= v.size())
|
|
||||||
throw index_error();
|
|
||||||
v.erase(v.begin() + i);
|
|
||||||
}, "erases element at index ``i``");
|
|
||||||
|
|
||||||
cl.def("empty", &Vector::empty, "checks whether the container is empty");
|
|
||||||
cl.def("size", &Vector::size, "returns the number of elements");
|
|
||||||
cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
|
|
||||||
cl.def("pop_back", &Vector::pop_back, "removes the last element");
|
|
||||||
|
|
||||||
cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
|
|
||||||
cl.def("reserve", &Vector::reserve, "reserves storage");
|
|
||||||
cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
|
|
||||||
cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
|
|
||||||
|
|
||||||
cl.def("clear", &Vector::clear, "clears the contents");
|
|
||||||
cl.def("swap", &Vector::swap, "swaps the contents");
|
|
||||||
|
|
||||||
cl.def("front", [](Vector &v) {
|
|
||||||
if (v.size()) return v.front();
|
|
||||||
else throw index_error();
|
|
||||||
}, "access the first element");
|
|
||||||
|
|
||||||
cl.def("back", [](Vector &v) {
|
|
||||||
if (v.size()) return v.back();
|
|
||||||
else throw index_error();
|
|
||||||
}, "access the last element ");
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// std::map, std::unordered_map
|
|
||||||
//
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/* Fallback functions */
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void map_if_insertion_operator(const Args &...) {}
|
|
||||||
template <typename, typename, typename... Args>
|
|
||||||
void map_assignment(const Args &...) {}
|
|
||||||
|
|
||||||
// Map assignment when copy-assignable: just copy the value
|
|
||||||
template <typename Map, typename Class_>
|
|
||||||
void map_assignment(
|
|
||||||
enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
|
|
||||||
using KeyType = typename Map::key_type;
|
|
||||||
using MappedType = typename Map::mapped_type;
|
|
||||||
|
|
||||||
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
|
||||||
auto it = m.find(k);
|
|
||||||
if (it != m.end()) {
|
|
||||||
it->second = v;
|
|
||||||
} else {
|
|
||||||
m.emplace(k, v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and
|
|
||||||
// reinserting
|
|
||||||
template <typename Map, typename Class_>
|
|
||||||
void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
|
|
||||||
&& is_copy_constructible<typename Map::mapped_type>::value,
|
|
||||||
Class_> &cl) {
|
|
||||||
using KeyType = typename Map::key_type;
|
|
||||||
using MappedType = typename Map::mapped_type;
|
|
||||||
|
|
||||||
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
|
|
||||||
// We can't use m[k] = v; because value type might not be default constructable
|
|
||||||
auto r = m.emplace(k, v);
|
|
||||||
if (!r.second) {
|
|
||||||
// value type is not copy assignable so the only way to insert it is to erase it
|
|
||||||
// first...
|
|
||||||
m.erase(r.first);
|
|
||||||
m.emplace(k, v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Map, typename Class_>
|
|
||||||
auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
|
||||||
-> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
|
|
||||||
<< std::declval<typename Map::mapped_type>(),
|
|
||||||
void()) {
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__repr__",
|
|
||||||
[name](Map &m) {
|
|
||||||
std::ostringstream s;
|
|
||||||
s << name << '{';
|
|
||||||
bool f = false;
|
|
||||||
for (auto const &kv : m) {
|
|
||||||
if (f) {
|
|
||||||
s << ", ";
|
|
||||||
}
|
|
||||||
s << kv.first << ": " << kv.second;
|
|
||||||
f = true;
|
|
||||||
}
|
|
||||||
s << '}';
|
|
||||||
return s.str();
|
|
||||||
},
|
|
||||||
"Return the canonical string representation of this map.");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename KeyType>
|
|
||||||
struct keys_view {
|
|
||||||
virtual size_t len() = 0;
|
|
||||||
virtual iterator iter() = 0;
|
|
||||||
virtual bool contains(const KeyType &k) = 0;
|
|
||||||
virtual bool contains(const object &k) = 0;
|
|
||||||
virtual ~keys_view() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename MappedType>
|
|
||||||
struct values_view {
|
|
||||||
virtual size_t len() = 0;
|
|
||||||
virtual iterator iter() = 0;
|
|
||||||
virtual ~values_view() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename KeyType, typename MappedType>
|
|
||||||
struct items_view {
|
|
||||||
virtual size_t len() = 0;
|
|
||||||
virtual iterator iter() = 0;
|
|
||||||
virtual ~items_view() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Map, typename KeysView>
|
|
||||||
struct KeysViewImpl : public KeysView {
|
|
||||||
explicit KeysViewImpl(Map &map) : map(map) {}
|
|
||||||
size_t len() override { return map.size(); }
|
|
||||||
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
|
|
||||||
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
|
|
||||||
bool contains(const object &) override { return false; }
|
|
||||||
Map ↦
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Map, typename ValuesView>
|
|
||||||
struct ValuesViewImpl : public ValuesView {
|
|
||||||
explicit ValuesViewImpl(Map &map) : map(map) {}
|
|
||||||
size_t len() override { return map.size(); }
|
|
||||||
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
|
|
||||||
Map ↦
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Map, typename ItemsView>
|
|
||||||
struct ItemsViewImpl : public ItemsView {
|
|
||||||
explicit ItemsViewImpl(Map &map) : map(map) {}
|
|
||||||
size_t len() override { return map.size(); }
|
|
||||||
iterator iter() override { return make_iterator(map.begin(), map.end()); }
|
|
||||||
Map ↦
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
|
|
||||||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
|
||||||
using KeyType = typename Map::key_type;
|
|
||||||
using MappedType = typename Map::mapped_type;
|
|
||||||
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
|
|
||||||
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
|
|
||||||
using KeysView = detail::keys_view<StrippedKeyType>;
|
|
||||||
using ValuesView = detail::values_view<StrippedMappedType>;
|
|
||||||
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
|
|
||||||
using Class_ = class_<Map, holder_type>;
|
|
||||||
|
|
||||||
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
|
||||||
// otherwise (e.g. both types are either module-local or converting) the map will be
|
|
||||||
// module-local.
|
|
||||||
auto *tinfo = detail::get_type_info(typeid(MappedType));
|
|
||||||
bool local = !tinfo || tinfo->module_local;
|
|
||||||
if (local) {
|
|
||||||
tinfo = detail::get_type_info(typeid(KeyType));
|
|
||||||
local = !tinfo || tinfo->module_local;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
|
||||||
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
|
|
||||||
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
|
|
||||||
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
|
|
||||||
|
|
||||||
// If key type isn't properly wrapped, fall back to C++ names
|
|
||||||
if (key_type_name == "%") {
|
|
||||||
key_type_name = detail::type_info_description(typeid(KeyType));
|
|
||||||
}
|
|
||||||
// Similarly for value type:
|
|
||||||
if (mapped_type_name == "%") {
|
|
||||||
mapped_type_name = detail::type_info_description(typeid(MappedType));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap KeysView[KeyType] if it wasn't already wrapped
|
|
||||||
if (!detail::get_type_info(typeid(KeysView))) {
|
|
||||||
class_<KeysView> keys_view(
|
|
||||||
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
|
|
||||||
keys_view.def("__len__", &KeysView::len);
|
|
||||||
keys_view.def("__iter__",
|
|
||||||
&KeysView::iter,
|
|
||||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
|
||||||
);
|
|
||||||
keys_view.def("__contains__",
|
|
||||||
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
|
|
||||||
// Fallback for when the object is not of the key type
|
|
||||||
keys_view.def("__contains__",
|
|
||||||
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
|
|
||||||
}
|
|
||||||
// Similarly for ValuesView:
|
|
||||||
if (!detail::get_type_info(typeid(ValuesView))) {
|
|
||||||
class_<ValuesView> values_view(scope,
|
|
||||||
("ValuesView[" + mapped_type_name + "]").c_str(),
|
|
||||||
pybind11::module_local(local));
|
|
||||||
values_view.def("__len__", &ValuesView::len);
|
|
||||||
values_view.def("__iter__",
|
|
||||||
&ValuesView::iter,
|
|
||||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Similarly for ItemsView:
|
|
||||||
if (!detail::get_type_info(typeid(ItemsView))) {
|
|
||||||
class_<ItemsView> items_view(
|
|
||||||
scope,
|
|
||||||
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
|
|
||||||
pybind11::module_local(local));
|
|
||||||
items_view.def("__len__", &ItemsView::len);
|
|
||||||
items_view.def("__iter__",
|
|
||||||
&ItemsView::iter,
|
|
||||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
cl.def(init<>());
|
|
||||||
|
|
||||||
// Register stream insertion operator (if possible)
|
|
||||||
detail::map_if_insertion_operator<Map, Class_>(cl, name);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__bool__",
|
|
||||||
[](const Map &m) -> bool { return !m.empty(); },
|
|
||||||
"Check whether the map is nonempty");
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__iter__",
|
|
||||||
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"keys",
|
|
||||||
[](Map &m) {
|
|
||||||
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"values",
|
|
||||||
[](Map &m) {
|
|
||||||
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"items",
|
|
||||||
[](Map &m) {
|
|
||||||
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
|
|
||||||
},
|
|
||||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def(
|
|
||||||
"__getitem__",
|
|
||||||
[](Map &m, const KeyType &k) -> MappedType & {
|
|
||||||
auto it = m.find(k);
|
|
||||||
if (it == m.end()) {
|
|
||||||
throw key_error();
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
},
|
|
||||||
return_value_policy::reference_internal // ref + keepalive
|
|
||||||
);
|
|
||||||
|
|
||||||
cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
|
|
||||||
auto it = m.find(k);
|
|
||||||
if (it == m.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
// Fallback for when the object is not of the key type
|
|
||||||
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
|
|
||||||
|
|
||||||
// Assignment provided only if the type is copyable
|
|
||||||
detail::map_assignment<Map, Class_>(cl);
|
|
||||||
|
|
||||||
cl.def("__delitem__", [](Map &m, const KeyType &k) {
|
|
||||||
auto it = m.find(k);
|
|
||||||
if (it == m.end()) {
|
|
||||||
throw key_error();
|
|
||||||
}
|
|
||||||
m.erase(it);
|
|
||||||
});
|
|
||||||
|
|
||||||
cl.def("__len__", &Map::size);
|
|
||||||
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
@ -1,61 +0,0 @@
|
|||||||
// Copyright (c) 2023 The pybind Community.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "detail/common.h"
|
|
||||||
#include "detail/descr.h"
|
|
||||||
#include "cast.h"
|
|
||||||
#include "pytypes.h"
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class type_caster<PyObject> {
|
|
||||||
public:
|
|
||||||
static constexpr auto name = const_name("object"); // See discussion under PR #4601.
|
|
||||||
|
|
||||||
// This overload is purely to guard against accidents.
|
|
||||||
template <typename T,
|
|
||||||
detail::enable_if_t<!is_same_ignoring_cvref<T, PyObject *>::value, int> = 0>
|
|
||||||
static handle cast(T &&, return_value_policy, handle /*parent*/) {
|
|
||||||
static_assert(is_same_ignoring_cvref<T, PyObject *>::value,
|
|
||||||
"Invalid C++ type T for to-Python conversion (type_caster<PyObject>).");
|
|
||||||
return nullptr; // Unreachable.
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(PyObject *src, return_value_policy policy, handle /*parent*/) {
|
|
||||||
if (src == nullptr) {
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
raise_from(PyExc_SystemError, "src != nullptr but PyErr_Occurred()");
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
if (policy == return_value_policy::take_ownership) {
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
if (policy == return_value_policy::reference
|
|
||||||
|| policy == return_value_policy::automatic_reference) {
|
|
||||||
return handle(src).inc_ref();
|
|
||||||
}
|
|
||||||
pybind11_fail("type_caster<PyObject>::cast(): unsupported return_value_policy: "
|
|
||||||
+ std::to_string(static_cast<int>(policy)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool load(handle src, bool) {
|
|
||||||
value = reinterpret_borrow<object>(src);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using cast_op_type = PyObject *;
|
|
||||||
|
|
||||||
explicit operator PyObject *() { return value.ptr(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
object value;
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
|
113
AUTHORS
113
AUTHORS
@ -1,112 +1 @@
|
|||||||
<!-- SPDX-FileCopyrightText: no
|
Teo Mrnjavac <teo@kde.org>
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
# MAINTAINER
|
|
||||||
|
|
||||||
Calamares maintainers through the years:
|
|
||||||
* Teo Mrnjavac <teo@kde.org> (maintainer -2017)
|
|
||||||
* Adriaan de Groot <groot@kde.org> (maintainer 2017-2022)
|
|
||||||
* Community (2022-)
|
|
||||||
|
|
||||||
Community maintainers are Adriaan de Groot, Anke Boersma, Evan James.
|
|
||||||
|
|
||||||
|
|
||||||
# CONTRIBUTORS
|
|
||||||
|
|
||||||
Calamares has received contributions of code, documentation, artwork
|
|
||||||
and moral support from (alphabetically by first name or nickname):
|
|
||||||
|
|
||||||
- Aaron Rainbolt
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Aleksey Samoilov
|
|
||||||
- Alf Gaida
|
|
||||||
- aliveafter1000
|
|
||||||
- Allen Welkie
|
|
||||||
- AlmAck
|
|
||||||
- Andrius Štikonas
|
|
||||||
- Anke Boersma
|
|
||||||
- Anubhav Choudhary
|
|
||||||
- Arjen Balfoort
|
|
||||||
- Arnaud Ferraris
|
|
||||||
- Artem Grinev
|
|
||||||
- artoo
|
|
||||||
- benne-dee
|
|
||||||
- Bernhard Landauer
|
|
||||||
- Bezzy1999
|
|
||||||
- Bill Auger
|
|
||||||
- Bob van der Linden
|
|
||||||
- Boria138
|
|
||||||
- Brian Morison
|
|
||||||
- Caio Jordão Carvalho
|
|
||||||
- Camilo Higuita
|
|
||||||
- Christophe Marin
|
|
||||||
- Collabora LTD
|
|
||||||
- Corey Lang
|
|
||||||
- crispg72
|
|
||||||
- dalto8
|
|
||||||
- Dan Simmons
|
|
||||||
- demmm
|
|
||||||
- DemonKiller
|
|
||||||
- Dominic Hayes
|
|
||||||
- El-Wumbus
|
|
||||||
- Emir SARI
|
|
||||||
- Emmanuel Arias
|
|
||||||
- Enrique Medina Gremaldos
|
|
||||||
- Erik Dubois
|
|
||||||
- Evan Goode
|
|
||||||
- Evan James
|
|
||||||
- Evan Maddock
|
|
||||||
- Ficelloo
|
|
||||||
- Frede Hundewadt
|
|
||||||
- Gabriel Craciunescu
|
|
||||||
- Gaël PORTAY
|
|
||||||
- GeckoLinux
|
|
||||||
- Harald Sitter
|
|
||||||
- Hector Martin
|
|
||||||
- Huang Jia Wen
|
|
||||||
- huxingyi
|
|
||||||
- Ivan Borzenkov
|
|
||||||
- Jeremy Attali
|
|
||||||
- Jeremy Whiting
|
|
||||||
- Jerrod Frost
|
|
||||||
- Jia Chao
|
|
||||||
- Johannes Kamprad
|
|
||||||
- Jonas Strassel
|
|
||||||
- Jonathan Esk-Riddell
|
|
||||||
- Kai Dohmen
|
|
||||||
- Kasra Hashemi
|
|
||||||
- Kevin Kofler
|
|
||||||
- Kyle Robertze
|
|
||||||
- Lisa Vitolo
|
|
||||||
- Lukas Märdian
|
|
||||||
- Mario Haustein
|
|
||||||
- Masato TOYOSHIMA
|
|
||||||
- Matti Hyttinen
|
|
||||||
- n3rdopolis
|
|
||||||
- Neal Gompa
|
|
||||||
- Nico 'dr460nf1r3'
|
|
||||||
- Omer I.S.
|
|
||||||
- Panda
|
|
||||||
- Paolo Dongilli
|
|
||||||
- Peter Jung
|
|
||||||
- Philip Müller
|
|
||||||
- Ramon Buldó
|
|
||||||
- Raul Rodrigo Segura
|
|
||||||
- Rohan Garg
|
|
||||||
- Santosh Mahto
|
|
||||||
- Scott Harvey
|
|
||||||
- shivanandvp
|
|
||||||
- Simon Quigley
|
|
||||||
- Sunderland93
|
|
||||||
- Sławomir Lach
|
|
||||||
- Taejun Park
|
|
||||||
- Tj
|
|
||||||
- Victor Fuentes
|
|
||||||
- Vitor Lopes
|
|
||||||
- vtriolet
|
|
||||||
- Walter Lapchynski
|
|
||||||
- Waneon Kim
|
|
||||||
- wiz64
|
|
||||||
|
|
||||||
> This list was updated to revision 283668cb0155c1c14739bb3b51db3d5d0b39c8e2 on February 17th 2024.
|
|
||||||
|
2067
CHANGES-3.2
2067
CHANGES-3.2
File diff suppressed because it is too large
Load Diff
571
CHANGES-3.3
571
CHANGES-3.3
@ -1,571 +0,0 @@
|
|||||||
<!-- SPDX-FileCopyrightText: no
|
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
This is the changelog for Calamares. For each release, the major changes and
|
|
||||||
contributors are listed. Note that Calamares does not have a historical
|
|
||||||
changelog -- this log starts with version 3.3.0. See CHANGES-3.2 for
|
|
||||||
the history of the 3.2 series (2018-05 - 2022-08).
|
|
||||||
|
|
||||||
# 3.3.12 (2024-11-21)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by given name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- This release repairs the Calamares configuration file which is
|
|
||||||
used by external Calamares modules -- calamares-extensions in particular.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *users* module always uses a 3-digit UMASK if one is specified.
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.11 (2024-11-05)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by given name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Jakob Petsovits
|
|
||||||
- Simon Quigley
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Nothing yet
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *unpackfs* now supports a `condition` configuration option for
|
|
||||||
conditional installation / unsquash. (thanks Simon)
|
|
||||||
- *unpackfsc* module imported from Calamares-extensions, and extended
|
|
||||||
with the same `condition` configuration.
|
|
||||||
- *partition* crash fixed when swap was using the wrong end-sector
|
|
||||||
in some GPT configurations. (thanks Jakob, #2367)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.10 (2024-10-21)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by given name):
|
|
||||||
- Aaron Rainbolt
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Evan James
|
|
||||||
- Neal Gompa
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Nothing yet
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *keyboard* Repaired summary messages with strange formatting. (#2364)
|
|
||||||
- *keyboard* Can update KDE Plasma configuration in Wayland. (thanks Neal, #2264)
|
|
||||||
- *locale* Repaired summary messages with strange formatting. (#2364)
|
|
||||||
- *partition* Module fixed unwanted behavior with the encryption checkbox. (thanks Aaron, #2376)
|
|
||||||
- *umount* Correctly unmounts the root filesystem of the target. (thanks Evan)
|
|
||||||
- *users* Supports a new `home_permissions` setting to override the
|
|
||||||
distro's `useradd` configuration of the umask. Supports octal and rwx-style
|
|
||||||
specifications of permissions. Other places that use permissions now also
|
|
||||||
support octal and rwx-style. (#2362)
|
|
||||||
- *welcome* Follows system styling colors (e.g. Dark Mode).
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.9 (2024-08-12)
|
|
||||||
|
|
||||||
Please note that if you are using the *luksbootkeyfile* module,
|
|
||||||
it must be placed before the *fstab* module in settings.conf. If it comes
|
|
||||||
after, then the keyfile will be missing from crypttab and the user will be
|
|
||||||
asked for their password multiple times.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by given name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Evan James
|
|
||||||
- Luca Matei Pintilie
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Improved schemas for configuration files
|
|
||||||
- Support for Interlingue in Qt 6.7
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- Placed *luksbootkeyfile* before *fstab* in the example `settings.conf` (#2356, Evan)
|
|
||||||
- *packages* module `xbcs` package manager now logs progress messages (#2359, Luca)
|
|
||||||
- *partition* module mentions creating a swap file in its summary (#2320, Adriaan)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.8 (2024-07-02)
|
|
||||||
|
|
||||||
The *partition* bug described below was reported by jghodd, then carefully
|
|
||||||
described and made reproducible by Joe Kamprad, examined by Evan James
|
|
||||||
and repaired by Adriaan de Groot. Many thanks to all who participated.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Evan James
|
|
||||||
- Lorenzo Faletra
|
|
||||||
- Tj
|
|
||||||
- Victor Fuentes
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- nothing in particular
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *contextualprocess* see *shellprocess*.
|
|
||||||
- *mount* module now correctly mounts luks and luks2-encrypted swap. (thanks Victor)
|
|
||||||
- *partition* avoids a crash with specific checkbox-presets. (thanks Evan)
|
|
||||||
- *partition* had a bug where manual partitioning on MBR systems might
|
|
||||||
skip the installation of a bootloader, even though the visible bootloader
|
|
||||||
combo-box showed that it would be installed. (see #2318)
|
|
||||||
- *partition* could calculate an incorrect partition size when installing to
|
|
||||||
very specific partition sizes, and now leaves a few more sectors for secondary
|
|
||||||
GPT tables. (thanks Tj)
|
|
||||||
- *shellprocess* now supports a *verbose* key (globally and per-command) which logs
|
|
||||||
command output line-by-line.
|
|
||||||
- *users* module defaults password salt to *yescrypt*. (thanks Lorenzo)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.7 (2024-06-20)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Eugene San
|
|
||||||
- Evan James
|
|
||||||
- Ivan Borzenkov
|
|
||||||
- Sohrab Behdani
|
|
||||||
- Vincent Penvern
|
|
||||||
- Vladislav Nepogodin
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Updated clang-formatting
|
|
||||||
- Some C++20 future-proofing (thanks Vladislav)
|
|
||||||
- CommandList (used by *contextualprocess* and *shellprocess*) now supports
|
|
||||||
globalstorage keys as substitutable variables.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *contextualprocess* see *shellprocess*.
|
|
||||||
- *fstab* module does not add an encryption keyfile if it does
|
|
||||||
not exist. (thanks Eugene)
|
|
||||||
- *initcpiocfg* has some new configuration settings to more carefully
|
|
||||||
adjust hooks for initcpio.
|
|
||||||
- *keyboard* module handles Persian (fa) layout better. (thanks Sohrab)
|
|
||||||
- *keyboard* module handles other non-ascii layout better. (thanks Ivan)
|
|
||||||
- *partition* module did not filter out invalid fstab entries;
|
|
||||||
they were not written, either, so no net change.
|
|
||||||
- *partition* module now has a configurable default check-state
|
|
||||||
for the encryption checkbox. (thanks Vincent)
|
|
||||||
- *shellprocess* commands now support globalstorage variables, which
|
|
||||||
are written as `${gs[key]}`, where `key` is a dotted string that
|
|
||||||
selects the globalstorage key to use (like in *contextualprocess*
|
|
||||||
variable-selectors) and `${gs[` and `]}` are literal characters.
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.6 (2024-04-16)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
- Eugene San
|
|
||||||
- Evan James
|
|
||||||
- Harald Sitter
|
|
||||||
- Mike Stemle
|
|
||||||
- Peter Jung
|
|
||||||
- Simon Quigley
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Various Qt6-related fixes.
|
|
||||||
- Calamares now prevents sleep and suspend while the installation is
|
|
||||||
running, so that unattended installs do not accidentally fall asleep.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *bootloader* Adds "splash" to kernel parameters if plymouth is present.
|
|
||||||
(thanks Eugene)
|
|
||||||
- *locale* Now picks the correct timezone for Dubai, Muscat, Tehran.
|
|
||||||
- *plymouthcfg* Use plymouth-set-default-theme to avoid issues with
|
|
||||||
configuration. (thanks Peter)
|
|
||||||
- *users* module now supports enrolling in Active Directory, if enabled.
|
|
||||||
(thanks Simon)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.5 (2024-03-03)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Evan James
|
|
||||||
- Peter Jung
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Calamares logs more information about how the executable was created
|
|
||||||
in the session log on startup. This will help in recreating the specific
|
|
||||||
configuration when bug reports are filed. (thanks Evan)
|
|
||||||
- The debug window now has better Qt6 compatibility.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *displaymanager* module can configure an alternate SDDM configuration file.
|
|
||||||
- *networkcfg* a bug affecting NetPlan + NetworkManager was fixed.
|
|
||||||
- *initcpiocfg* Add microcode hook to initcpiocfg
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.4 (2024-02-27)
|
|
||||||
|
|
||||||
In this release, process jobmodules -- a particular kind of module
|
|
||||||
recognizable by `type: job` and `interface: process` in the descriptor
|
|
||||||
file -- undergo a large change to resemble *shellprocess* more.
|
|
||||||
|
|
||||||
Users of process jobmodules are encouraged to double-check the Functionality
|
|
||||||
of those modules in this release.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Victor Fuentes
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Process jobs (a job type provided by Calamares core) now share more
|
|
||||||
code with *contextualprocess* and *shellprocess* jobs. The execution
|
|
||||||
mechanism is the same, and always invokes the shell, whether the command
|
|
||||||
runs in the host or in the target system. It is no longer necessary to
|
|
||||||
add `/bin/sh` in the *command* key -- this is always present.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *contextualprocess* and *shellprocess* can now set environment variables
|
|
||||||
as part of the configuration. See *shellprocess* documentation for details.
|
|
||||||
This is optional, and does not do anything that could not already be done
|
|
||||||
by putting `export VAR=value ;` in front of the command before.
|
|
||||||
- *partition* fixed a bug with an uninitialized variable. (thanks Victor)
|
|
||||||
- *shellprocess* (and therefore also *contextualprocess* and process
|
|
||||||
jobmodules) now substitutes `${LANG}` in commands with the language
|
|
||||||
selected in the user-interface of Calamares.
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.3 (2024-02-24)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
|
|
||||||
Translations have been updated (3.3.2 skipped that step).
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Core libraries *libcalamares* and *libcalamaresui* now build with
|
|
||||||
hidden visibility by default, as a step towards ABI stability.
|
|
||||||
- A runtime crash caused by (mis?)use of Qt UniqueConnection which
|
|
||||||
shows up in Debug builds was resolved.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *interactiveterminal* can use konsole in Qt6 too. (thanks Anke)
|
|
||||||
- *plasmalnf* module ported to Plasma 6. (thanks Anke)
|
|
||||||
- *welcomeq* example extended to include Markdown syntax. (thanks Anke)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.2 (2024-02-19)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Aaron Rainbolt
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
- Evan James
|
|
||||||
- Jonathan Riddell
|
|
||||||
- Lukas Märdian
|
|
||||||
- Tj
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Slideshow support code (QML) now ported to Qt6 and made available
|
|
||||||
as two separate directories of support-code. (thanks Jon)
|
|
||||||
- Compatibility with Qt versions prior to 5.15.5 has been removed.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *fstab* bug fixed where BTRFS messes up the partition layout. (thanks Tj)
|
|
||||||
- *networkcfg* on NetPlan-enabled systems, configure NetworkManager
|
|
||||||
with the live-system's NetPlan settings. (thanks Lukas)
|
|
||||||
- *partition* module can now also define unencrypted partitions
|
|
||||||
when encryption is used. (thanks Aaron)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.1 (2024-01-15)
|
|
||||||
|
|
||||||
This release sets `BUILD_APPDATA` and `BUILD_APSTREAM` to default to **OFF**,
|
|
||||||
where previously they defaulted to **ON**. When enabled, the dependencies for
|
|
||||||
both features are required -- previously they would silently switch off if
|
|
||||||
the dependencies were not found. Distributions are strongly advised to check
|
|
||||||
their package-building instructions.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Aleksey Samoilov
|
|
||||||
- Emir Sari
|
|
||||||
- Simon Quigley
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- There has been internal code re-organization (e.g. not using functions
|
|
||||||
named `tr()`) to help translation tools.
|
|
||||||
- Strings everywhere have been given more context. (thanks Emir)
|
|
||||||
- In CMake, "view" is no longer accepted as an alias of the module
|
|
||||||
type "viewmodule" in function `calamares_add_plugin()`.
|
|
||||||
- Plain Ubuntu builds have been added to the CI roster. (thanks Simon)
|
|
||||||
- Commands that run in the target system (in the chroot) no longer
|
|
||||||
use the TMP-related environment variables from the host. #2269
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- The *displaymanager* module configuration for `greetd` has some more
|
|
||||||
options now. (thanks Aleksey)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0 (2023-12-12)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Alberto Salvia Novella
|
|
||||||
- Christophe Marin
|
|
||||||
- Evan Maddock
|
|
||||||
- Frede Hundewadt
|
|
||||||
|
|
||||||
Since this is the first non-alpha release of 3.3.0, we would like to thank
|
|
||||||
all the contributors to a year and a half of alpha releases, six in all.
|
|
||||||
Distributions are **strongly** advices to take the release notes of
|
|
||||||
the alpha's into account as well.
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- No changes of note.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *users* and *usersq* no longer support the password requirement 'nonempty'.
|
|
||||||
Use 'minLength: 1' instead. The example configuration allows the user to
|
|
||||||
choose any password at all, but also contains suggestions for other
|
|
||||||
password-requirements schemes. (thanks Alberto)
|
|
||||||
- *users* now can use stronger password hashes, if `crypt_gensalt()` is
|
|
||||||
available in the *crypt* library. (thanks Evan)
|
|
||||||
- *machineid* module supports several variations of writing /etc/machine-id .
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha6 (2023-11-16)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
|
|
||||||
This is a hotfix release because -alpha5 didn't compile,
|
|
||||||
and Anke repaired the partition unit-tests when building with Qt6.
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha5 (2023-11-13)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Alejo Fernandez
|
|
||||||
- Anke Boersma
|
|
||||||
- Christophe Marin
|
|
||||||
- Emir Sari
|
|
||||||
- Evan James
|
|
||||||
- Gaël PORTAY
|
|
||||||
- Gecko Linux
|
|
||||||
- Jeremy Whiting
|
|
||||||
- Neal Gompa
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Boost::Python is no longer a dependency, Calamares uses a bundled copy
|
|
||||||
of pybind11 instead. This speeds up compilation and reducese the
|
|
||||||
dependency tree a great deal. You can set `WITH_PYBIND11=OFF` in the
|
|
||||||
build to keep Boost::Python and all the binary-compatibility problems
|
|
||||||
it entails.
|
|
||||||
- Coding style now wants clang-format 15 or 16, but no longer needs astyle.
|
|
||||||
There is also a clang-tidy file for additional styling support.
|
|
||||||
- Ongoing translation improvements. (thanks Emir)
|
|
||||||
- Translations for bqi (Luri), es_AR (Castellano), eo (Esperanto),
|
|
||||||
ka (Georgian). In **non-release** builds (e.g. between releases,
|
|
||||||
so for developers building directly from git) all translations are
|
|
||||||
enabled, even the ones with no translations at all.
|
|
||||||
- The logging format in the `session.log` file and on-screen is now
|
|
||||||
more similar, although the file contains a lot more per-line information.
|
|
||||||
- The INSTALL_CONFIG option has been restored. It is still a terrible
|
|
||||||
idea to fork the repository to modify the config files, and you
|
|
||||||
probably should have a calamares-config package with those files
|
|
||||||
instead, there are packaging workflows that can usefully patch-and-
|
|
||||||
install configuration files. The option defaults to OFF.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- All QML modules now have a Qt6-compatible set of QML files as well. (thanks Anke)
|
|
||||||
- *packagechooser* supports AppStream 1.0 API.
|
|
||||||
- *unpackfs* now uses the `-S` option to rsync for sparse file support. (thanks Jeremy)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha4 (2023-10-13)
|
|
||||||
|
|
||||||
Another closing-in-on-3.3.0 release! One of the big changes is that
|
|
||||||
Calamares -- the core and nearly all of the modules in this repository --
|
|
||||||
are compatible with Qt6. That is, it compiles. Functionality has not
|
|
||||||
been tested, but early-testing distributions are encouraged to submit
|
|
||||||
pull requests to improve the code.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
- Emir Sari
|
|
||||||
- Evan James
|
|
||||||
- Hector Martin
|
|
||||||
- Ivan Borzenkov
|
|
||||||
- Simon Quigley
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Qt6 compatibility. You can choose Qt5 (with KDE Frameworks 5) as before,
|
|
||||||
or choose Qt6 (with KDE Frameworks 6). This means that a Qt6-based Linux
|
|
||||||
distribution can use Calamares without needing an extra version of Qt.
|
|
||||||
Note that some KDE Frameworks are required as well, and those need to be
|
|
||||||
Qt6-based also (and are not released as of September 2023).
|
|
||||||
- QML-based modules are also supported in Qt6, but the QML is likely to
|
|
||||||
be source-incompatible. The *welcomeq* module shipped with Calamares
|
|
||||||
now has two `.qrc` files and uses the `${QT_VERSION_SUFFIX}` variable
|
|
||||||
to pick one of the two depending on the Qt version being used.
|
|
||||||
Other modules are likely to follow the same pattern.
|
|
||||||
- C++ namespaces have been shuffled around and `CalamaresUtils` has been
|
|
||||||
retired. This has an effect on all C++ plugins, since this is neither
|
|
||||||
a binary- nor source-compatible change.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *keyboard* module can now be explicitly configured to use X11 keyboard
|
|
||||||
settings or the FreeDesktop locale1 DBus service. The latter is most
|
|
||||||
useful for Calamares as an "initial setup" system, not an installer,
|
|
||||||
in a Wayland session. (thanks Hector)
|
|
||||||
- *keyboard* module now writes X11 layout configuration with variants
|
|
||||||
for all non-ASCII (e.g. us) layouts. (thanks Ivan)
|
|
||||||
- *keyboard* module now can configure keyboard switch. (thanks Ivan)
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha3 (2023-08-28)
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Aleksey Samoilov
|
|
||||||
- Anke Boersma
|
|
||||||
- Arjen Balfoort
|
|
||||||
- Boria138
|
|
||||||
- Brian Morison
|
|
||||||
- Emir Sari
|
|
||||||
- Evan Goode
|
|
||||||
- Evan James
|
|
||||||
- Ficelloo
|
|
||||||
- Hector Martin
|
|
||||||
- Jeremy Attall
|
|
||||||
- Johannes Kamprad
|
|
||||||
- Kasta Hashemi
|
|
||||||
- Kevin Kofler
|
|
||||||
- Mario Haustein
|
|
||||||
- Masato TOYOSHIMA
|
|
||||||
- Panda
|
|
||||||
- Paolo Dongilli
|
|
||||||
- Peter Jung
|
|
||||||
- Philip Müller
|
|
||||||
- Shivanand
|
|
||||||
- Sławomir Lach
|
|
||||||
- Sunderland93
|
|
||||||
- wiz64
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- Incompatible module-configuration changes, see #1438.
|
|
||||||
- Branding entries use ${var} instead of @{var} for substitutions,
|
|
||||||
in line with all the other substitution mechanisms used from C++
|
|
||||||
core. See documentation in `branding.desc`.
|
|
||||||
- Boost::Python requires at least version 1.72.
|
|
||||||
- KDE Frameworks must be version 5.58 or later.
|
|
||||||
- The `INSTALL_CONFIG` option has been removed. If you are installing
|
|
||||||
the example configuration files from the Calamares repository, just
|
|
||||||
stop. That was never a good idea, and you should keep your configs elsewhere.
|
|
||||||
- Progress percentage during install can now be localized. (thanks Emir)
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *dracut* added a configurable kernel name. (thanks Anke)
|
|
||||||
- *initcpiocfg* orders hookds slightly differently. (thanks Peter)
|
|
||||||
- *localeq* moved to using Drawer instead of ComboBox in UI. (thanks Anke)
|
|
||||||
- *keyboardq* moved to using Drawer instead of ComboBox in UI. (thanks Anke)
|
|
||||||
- *netinstall* now has a new *noncheckable* option for groups, which prevent
|
|
||||||
it a group from being checked/uncheckd as a whole. You can still check
|
|
||||||
individual items **in** the group though. (thanks Shivanand)
|
|
||||||
- *partition* can now pick LUKS or LUKS2. (thanks Jeremy)
|
|
||||||
- *zfs* creates a hostid through zgenhostid.
|
|
||||||
- *zfshostid* new module to copy zfs generated /etc/hostid
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha2 (2022-08-23)
|
|
||||||
|
|
||||||
Second alpha release, with updated ABI compatibility checking,
|
|
||||||
some 3.3.0 release goals, new features in modules and important bugfixes.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Anke Boersma
|
|
||||||
- Evan James
|
|
||||||
- Shivanand
|
|
||||||
- Vitor Lopes
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
|
|
||||||
A core **TODO** is moving all library code into the `Calamares` namespace,
|
|
||||||
dropping the `CalamaresUtils` namespace. Modern C++ supports nested namespaces,
|
|
||||||
so in some cases we can use those. This has a drastic effect on ABI compatibility,
|
|
||||||
though, as functions move from one namespace to another. This needs to be
|
|
||||||
completed before a 3.3.0 with ABI stability is released.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
|
|
||||||
Module schemas have been updated to reflect all the incompatible changes.
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-alpha1 (2022-06-27)
|
|
||||||
|
|
||||||
Initial 3.3.0 alpha release to check the release scripts &c.
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Adriaan de Groot
|
|
||||||
- Aleksey Samoilov
|
|
||||||
- Anke Boersma
|
|
||||||
- Dan Simmons
|
|
||||||
- Evan James
|
|
||||||
- Peter Jung
|
|
||||||
|
|
||||||
|
|
||||||
# 3.3.0-pre-alpha (unreleased) #
|
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
|
||||||
- Anke Boersma
|
|
||||||
- Anubhav Choudhary
|
|
||||||
- Evan James
|
|
||||||
- Vitor Lopes
|
|
||||||
|
|
||||||
This is a "minor" version change, but the size of the changes is very
|
|
||||||
large. Configuration files from previous versions of Calamares will
|
|
||||||
**certainly** need to be re-validated. Take heed of the many changes
|
|
||||||
in the *Modules* heading, below.
|
|
||||||
|
|
||||||
Users (distributions) are **strongly** advised to use the tools
|
|
||||||
for configuration validation (`ci/configvalidator.py`) to check
|
|
||||||
that the distribution configuration files follow the current schema.
|
|
||||||
|
|
||||||
## Project ##
|
|
||||||
- The C++ code in the project is now formatted with clang-format 12 or 13,
|
|
||||||
with the coding-style as found in `.clang-format`; there are minor
|
|
||||||
differences from the tool, compared to the clang-format 9 usually applied
|
|
||||||
to Calamares 3.2.
|
|
||||||
- The CMake code in the project is now formatted with gersemi 0.7.5.
|
|
||||||
|
|
||||||
## Core ##
|
|
||||||
- CMake 3.16, Qt 5.15 are now required; the newer CMake is to support
|
|
||||||
new features (also for KDE Frameworks), Qt is the current LTS version.
|
|
||||||
- Running `calamares -d` no longer enforces a single-application
|
|
||||||
(it is for debugging purposes, after all).
|
|
||||||
- Python 3.6 or later is now required, to allow for F-strings in
|
|
||||||
Python code and allow other tidy-ups in the Python modules.
|
|
||||||
Boost::Python now requires 1.67 or later (for CMake support).
|
|
||||||
- The log file now **always** contains a debug-log, and the `-D` flag
|
|
||||||
primarily controls what is printed to stdout. By default, stdout
|
|
||||||
only gets errors; use `-D6` to match stdout with the file. Use `-D8`
|
|
||||||
to get an extra-verbose log file **and** verbose stdout.
|
|
||||||
|
|
||||||
## Modules ##
|
|
||||||
- *bootloader* now supports more options when building the kernel
|
|
||||||
command-line. (Thanks Evan)
|
|
||||||
- *bootloader* no longer supports `@@`-style suffixes for unique-EFI-id
|
|
||||||
generation. Use `${}` instead.
|
|
||||||
- *displaymanager* no longer supports the discontinued *kdm* display manager.
|
|
||||||
- *fstab* configuration has been completely re-done. Many configuration
|
|
||||||
options have moved to the *mount* module. See #1993
|
|
||||||
- *grubcfg* changed the key *keepDistributor* to *keep_distributor*.
|
|
||||||
Please update configurations.
|
|
||||||
- *mount* now does most of the mounting; options that were in *fstab*
|
|
||||||
have moved here. See #1993
|
|
||||||
- *oemid* now uses consistent variable replacement (e.g. KMacroExpander)
|
|
||||||
and does not support `@@DATE@@` anymore (use `${DATE}`).
|
|
||||||
- *partition* requires KPMCore 21.12 (e.g. KPMCore 4.2 API, or later).
|
|
||||||
- *partition* can now skip installing the bootloader in more scenarios.
|
|
||||||
#1632 (Thanks Anubhav)
|
|
||||||
- *preservefiles* follows `${}` variable syntax instead of `@@`.
|
|
||||||
|
|
932
CMakeLists.txt
932
CMakeLists.txt
@ -1,774 +1,268 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
project( calamares CXX )
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
# Individual files may have different licenses (like the CMake
|
|
||||||
# infrastructure, which is BSD-2-Clause licensed). Check the SPDX
|
|
||||||
# identifiers in each file.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Generally, this CMakeLists.txt will find all the dependencies for Calamares
|
|
||||||
# and complain appropriately. See below (later in this file) for CMake-level
|
|
||||||
# options. There are some "secret" options as well:
|
|
||||||
#
|
|
||||||
# SKIP_MODULES : a space or semicolon-separated list of directory names
|
|
||||||
# under src/modules that should not be built.
|
|
||||||
# USE_<foo> : fills in SKIP_MODULES for modules called <foo>-<something>.
|
|
||||||
# WITH_<foo> : try to enable <foo> (these usually default to ON). For
|
|
||||||
# a list of WITH_<foo> grep CMakeCache.txt after running
|
|
||||||
# CMake once. These affect the ABI offered by Calamares.
|
|
||||||
# - PYBIND11 (use bundled pybind11, default ON, needs WITH_PYTHON)
|
|
||||||
# - PYTHON (enable Python Job modules, default ON if Python is found)
|
|
||||||
# - QML (enable QML UI View modules, default ON)
|
|
||||||
# - QT6 (use Qt6 rather than Qt5, default to OFF)
|
|
||||||
# The WITH_* options affect the ABI of Calamares: you must
|
|
||||||
# build (C++) modules for Calamares with the same WITH_*
|
|
||||||
# settings, or they may not load at all.
|
|
||||||
# BUILD_<foo> : choose additional things to build
|
|
||||||
# - APPDATA (use AppData in packagechooser, requires QtXml)
|
|
||||||
# - APPSTREAM (use AppStream in packagechooser, requires libappstream-qt)
|
|
||||||
# - BUILD_CRASH_REPORTING (uses KCrash, rather than Calamares internal, for crash reporting)
|
|
||||||
# - SCHEMA_TESTING (requires Python, see ci/configvalidator.py)
|
|
||||||
# - TESTING (standard CMake option)
|
|
||||||
# DEBUG_<foo> : special developer flags for debugging.
|
|
||||||
# PYTHONLIBS_VERSION : if set on the command-line, use a specific Python version
|
|
||||||
#
|
|
||||||
# Example usage:
|
|
||||||
#
|
|
||||||
# cmake . -DSKIP_MODULES="partition luksbootkeycfg"
|
|
||||||
#
|
|
||||||
# To obtain the version number of calamares, run CMake in script mode, e.g.
|
|
||||||
# cmake -P CMakeLists.txt
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
|
# The partition manager uses ECM but ECMConfig.cmake
|
||||||
|
# will complain if we require CMake less than 2.8.13,
|
||||||
|
# so never change this.
|
||||||
|
cmake_minimum_required( VERSION 2.8.12 )
|
||||||
|
|
||||||
set(CALAMARES_VERSION 3.3.12)
|
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" )
|
||||||
set(CALAMARES_RELEASE_MODE ON) # Set to ON during a release
|
|
||||||
|
|
||||||
if(CMAKE_SCRIPT_MODE_FILE)
|
if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/CMakeModules/ExtendedVersion.cmake)
|
message( STATUS "Found Clang ${CMAKE_CXX_COMPILER_VERSION}, setting up Clang-specific compiler flags." )
|
||||||
set(CMAKE_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -std=c99" )
|
||||||
extend_version( ${CALAMARES_VERSION} ${CALAMARES_RELEASE_MODE} _vshort _vlong )
|
set( CMAKE_C_FLAGS_DEBUG "-g" )
|
||||||
message("${_vlong}")
|
set( CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" )
|
||||||
return()
|
set( CMAKE_C_FLAGS_RELEASE "-O4 -DNDEBUG" )
|
||||||
|
set( CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g" )
|
||||||
|
|
||||||
|
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -std=c++14" )
|
||||||
|
set( CMAKE_CXX_FLAGS_DEBUG "-g" )
|
||||||
|
set( CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG" )
|
||||||
|
set( CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG" )
|
||||||
|
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g" )
|
||||||
|
|
||||||
|
set( CMAKE_TOOLCHAIN_PREFIX "llvm-" )
|
||||||
|
|
||||||
|
set( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined" )
|
||||||
|
else()
|
||||||
|
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99" )
|
||||||
|
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wl,--no-undefined" )
|
||||||
|
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wl,--fatal-warnings -Wnon-virtual-dtor -Woverloaded-virtual -Werror=return-type" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Massage the version for CMake if there is a version-suffix
|
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
string(REGEX REPLACE "-.*" "" CALAMARES_VERSION_SHORT "${CALAMARES_VERSION}")
|
if( CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9 OR
|
||||||
# And preserve the original version (suffix and all) because project() overwrites
|
CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.9 )
|
||||||
# .. but if we're doing non-release builds, this gets replaced with git versioning.
|
message( STATUS "Found GNU g++ ${CMAKE_CXX_COMPILER_VERSION}, enabling colorized error messages." )
|
||||||
set(CALAMARES_VERSION_LONG "${CALAMARES_VERSION}")
|
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=auto" )
|
||||||
|
endif()
|
||||||
project(CALAMARES VERSION ${CALAMARES_VERSION_SHORT} LANGUAGES C CXX HOMEPAGE_URL "https://calamares.io/")
|
|
||||||
|
|
||||||
if(NOT CALAMARES_RELEASE_MODE AND CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
|
||||||
message(FATAL_ERROR "Do not build development versions in the source-directory.")
|
|
||||||
endif()
|
endif()
|
||||||
# Calamares in the 3.3 series promises ABI compatbility, so it sets a
|
|
||||||
# .so-version equal to the series number. We use ci/abicheck.sh to
|
|
||||||
# keep track of this. Note that the **alpha** releases also have
|
|
||||||
# such an .so-version, but are not ABI-stable yet.
|
|
||||||
set(CALAMARES_SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
|
||||||
|
|
||||||
### OPTIONS
|
cmake_policy( SET CMP0023 OLD )
|
||||||
#
|
cmake_policy( SET CMP0028 NEW ) # double colons in KF5::Foo and Qt5::Foo are necessarily IMPORTED or ALIAS targets, don't search further
|
||||||
option(INSTALL_POLKIT "Install Polkit configuration" ON)
|
|
||||||
option(INSTALL_COMPLETION "Install shell completions" OFF)
|
|
||||||
option(INSTALL_CONFIG "Install configuration files" OFF)
|
|
||||||
# When adding WITH_* that affects the ABI offered by libcalamares,
|
|
||||||
# also update libcalamares/CalamaresConfig.h.in
|
|
||||||
option(WITH_PYBIND11 "Use bundled pybind11 instead of Boost::Python" ON)
|
|
||||||
option(WITH_PYTHON "Enable Python modules API." ON)
|
|
||||||
option(WITH_QML "Enable QML UI options." ON)
|
|
||||||
option(WITH_QT6 "Use Qt6 instead of Qt5" OFF)
|
|
||||||
#
|
|
||||||
# Additional parts to build that do not affect ABI
|
|
||||||
option(BUILD_SCHEMA_TESTING "Enable schema-validation-tests" ON)
|
|
||||||
# Options for the calamares executable
|
|
||||||
option(BUILD_CRASH_REPORTING "Enable crash reporting with KCrash." ON)
|
|
||||||
|
|
||||||
# Possible debugging flags are:
|
# Keep cmake 3.0 quiet
|
||||||
# - DEBUG_TIMEZONES draws latitude and longitude lines on the timezone
|
if( POLICY CMP0043 )
|
||||||
# widget and enables chatty debug logging, for dealing with the timezone
|
cmake_policy( SET CMP0043 OLD )
|
||||||
# location database.
|
endif()
|
||||||
# - DEBUG_FILESYSTEMS does extra logging and checking when looking at
|
|
||||||
# partition configuration. Lists known KPMCore FS types.
|
|
||||||
# - DEBUG_PARTITION_UNSAFE (see partition/CMakeLists.txt)
|
|
||||||
# - DEBUG_PARTITION_BAIL_OUT (see partition/CMakeLists.txt)
|
|
||||||
|
|
||||||
# Special handling for Python versions:
|
include( MacroOptionalFindPackage )
|
||||||
# - If you set PYTHONLIBS_VERSION on the command-line, then
|
include( MacroLogFeature )
|
||||||
# that **exact** version will be searched for, and no other.
|
|
||||||
# - If you do not set PYTHONLIBS_VERSION on the command-line,
|
|
||||||
# any suitable version will be found -- but this can fail if
|
|
||||||
# you have multiple Python versions installed, only some of
|
|
||||||
# which include the development headers.
|
|
||||||
|
|
||||||
### USE_*
|
set( QT_VERSION 5.6.0 )
|
||||||
#
|
|
||||||
# By convention, when there are multiple modules that implement similar
|
|
||||||
# functionality, and it only makes sense to have **at most one** of them
|
|
||||||
# enabled at any time, those modules are named <foo>-<implementation>.
|
|
||||||
# For example, services-systemd and services-openrc.
|
|
||||||
#
|
|
||||||
# Setting up SKIP_MODULES to ignore "the ones you don't want" can be
|
|
||||||
# annoying and error-prone (e.g. if a new module shows up). The USE_*
|
|
||||||
# modules provide a way to do automatic selection. To pick exactly
|
|
||||||
# one of the implementations from group <foo>, set USE_<foo> to the
|
|
||||||
# name of the implementation. If USE_<foo> is unset, or empty, then
|
|
||||||
# all the implementations are enabled (this just means they are
|
|
||||||
# **available** to `settings.conf`, not that they are used).
|
|
||||||
#
|
|
||||||
# To explicitly disable a set of modules, set USE_<foo>=none
|
|
||||||
# (e.g. the literal string none), which won't match any of the
|
|
||||||
# modules but is handled specially.
|
|
||||||
#
|
|
||||||
# The following USE_* functionalities are available:
|
|
||||||
# - *services* picks one of the two service-configuration modules,
|
|
||||||
# for either systemd or openrc. This defaults to empty so that
|
|
||||||
# **both** modules are available.
|
|
||||||
set(USE_services "" CACHE STRING "Select the services module to use")
|
|
||||||
|
|
||||||
|
find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Core Gui Widgets LinguistTools Svg Quick QuickWidgets )
|
||||||
|
find_package( YAMLCPP 0.5.1 REQUIRED )
|
||||||
|
find_package( PolkitQt5-1 REQUIRED )
|
||||||
|
|
||||||
|
option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON )
|
||||||
|
option( WITH_CRASHREPORTER "Build with CrashReporter" ON )
|
||||||
|
option( INSTALL_CONFIG "Install configuration files" ON)
|
||||||
|
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF )
|
||||||
|
|
||||||
|
if( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/libcrashreporter-qt/CMakeLists.txt" )
|
||||||
|
message( STATUS "Build of crashreporter disabled." )
|
||||||
|
set( WITH_CRASHREPORTER OFF )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro_optional_find_package( PythonLibs 3.3 )
|
||||||
|
macro_log_feature(
|
||||||
|
PYTHONLIBS_FOUND
|
||||||
|
"Python"
|
||||||
|
"C interface libraries for the Python 3 interpreter."
|
||||||
|
"http://python.org"
|
||||||
|
FALSE "3.3"
|
||||||
|
"Python 3 is used for some Calamares job modules."
|
||||||
|
)
|
||||||
|
|
||||||
|
if ( PYTHONLIBS_FOUND )
|
||||||
|
include( BoostPython3 )
|
||||||
|
find_boost_python3( 1.54.0 ${PYTHONLIBS_VERSION_STRING} CALAMARES_BOOST_PYTHON3_FOUND )
|
||||||
|
macro_log_feature(
|
||||||
|
CALAMARES_BOOST_PYTHON3_FOUND
|
||||||
|
"Boost.Python"
|
||||||
|
"A C++ library which enables seamless interoperability between C++ and Python 3."
|
||||||
|
"http://www.boost.org"
|
||||||
|
FALSE "1.54.0"
|
||||||
|
"Boost.Python is used for interfacing with Calamares job modules written in Python 3."
|
||||||
|
)
|
||||||
|
|
||||||
|
macro_optional_find_package( PythonQt )
|
||||||
|
macro_log_feature( PYTHONQT_FOUND
|
||||||
|
"PythonQt"
|
||||||
|
"A Python embedding solution for Qt applications."
|
||||||
|
"http://pythonqt.sourceforge.net"
|
||||||
|
FALSE "3.1"
|
||||||
|
"PythonQt is used for the Python modules API."
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if ( PYTHONLIBS_NOTFOUND OR NOT CALAMARES_BOOST_PYTHON3_FOUND )
|
||||||
|
set( WITH_PYTHON OFF )
|
||||||
|
endif()
|
||||||
|
if ( PYTHONLIBS_NOTFOUND OR NOT PYTHONQT_FOUND )
|
||||||
|
set( WITH_PYTHONQT OFF )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
###
|
||||||
### Calamares application info
|
### Calamares application info
|
||||||
#
|
###
|
||||||
set(CALAMARES_ORGANIZATION_NAME "Calamares")
|
set( CALAMARES_ORGANIZATION_NAME "Calamares" )
|
||||||
set(CALAMARES_ORGANIZATION_DOMAIN "github.com/calamares")
|
set( CALAMARES_ORGANIZATION_DOMAIN "github.com/calamares" )
|
||||||
set(CALAMARES_APPLICATION_NAME "Calamares")
|
set( CALAMARES_APPLICATION_NAME "Calamares" )
|
||||||
set(CALAMARES_DESCRIPTION_SUMMARY "The distribution-independent installer framework")
|
set( CALAMARES_DESCRIPTION_SUMMARY "The distribution-independent installer framework" )
|
||||||
|
set( CALAMARES_TRANSLATION_LANGUAGES ar ast bg ca cs_CZ da de el en en_GB es_MX es eu fr hr hu id is it_IT ja lt nl pl pt_BR pt_PT ro ru sk sv th tr_TR zh_CN zh_TW )
|
||||||
|
|
||||||
### Transifex (languages) info
|
### Bump version here
|
||||||
#
|
set( CALAMARES_VERSION_MAJOR 3 )
|
||||||
# complete = 100% translated,
|
set( CALAMARES_VERSION_MINOR 0 )
|
||||||
# good = nearly complete (use own judgement, right now >= 75%)
|
set( CALAMARES_VERSION_PATCH 1 )
|
||||||
# ok = incomplete (more than 25% untranslated, at least 5% translated),
|
set( CALAMARES_VERSION_RC 0 )
|
||||||
# incomplete = <5% translated, placeholder in tx; these are not included.
|
|
||||||
#
|
|
||||||
# Language en (source language) is added later. It isn't listed in
|
|
||||||
# Transifex either. Get the list of languages and their status
|
|
||||||
# from https://app.transifex.com/calamares/calamares/ , or (preferably)
|
|
||||||
# use ci/txstats.py to automatically check.
|
|
||||||
#
|
|
||||||
# When adding a new language, take care that it is properly loaded
|
|
||||||
# by the translation framework. Languages with alternate scripts
|
|
||||||
# (sr@latin in particular) or location (ca@valencia) need special
|
|
||||||
# handling in libcalamares/locale/Translation.h .
|
|
||||||
#
|
|
||||||
# NOTE: move ie (Interlingue) to _ok once Qt supports it.
|
|
||||||
# NOTE: update these lines by running `txstats.py`, or for full automation
|
|
||||||
# `txstats.py -e`. See also
|
|
||||||
#
|
|
||||||
# Total 80 languages
|
|
||||||
set( _tx_complete de en es_AR fi_FI hr hu ja lt tr_TR uk zh_TW )
|
|
||||||
set( _tx_good az az_AZ be bg ca cs_CZ es fr fur he hi is it_IT ko
|
|
||||||
pl pt_BR pt_PT ru si sq sv zh_CN )
|
|
||||||
set( _tx_ok ar as ast bn ca@valencia da el en_GB eo es_MX et eu fa
|
|
||||||
gl id ka ml mr nb nl oc ro sk sl sr sr@latin tg th vi )
|
|
||||||
set( _tx_incomplete bqi es_PR gu ie ja-Hira kk kn lo lv mk ne_NP
|
|
||||||
ro_RO ta_IN te ur uz zh zh_HK )
|
|
||||||
# Total 80 languages
|
|
||||||
|
|
||||||
### Required versions
|
set( CALAMARES_VERSION ${CALAMARES_VERSION_MAJOR}.${CALAMARES_VERSION_MINOR}.${CALAMARES_VERSION_PATCH} )
|
||||||
#
|
set( CALAMARES_VERSION_SHORT "${CALAMARES_VERSION}" )
|
||||||
# See DEPENDENCIES section below.
|
if( CALAMARES_VERSION_RC )
|
||||||
|
set( CALAMARES_VERSION ${CALAMARES_VERSION}rc${CALAMARES_VERSION_RC} )
|
||||||
|
endif()
|
||||||
|
|
||||||
# The default build is with Qt5, but that is increasingly not the
|
# additional info for non-release builds
|
||||||
# version installed-by-default on Linux systems. Upgrade the default
|
if( NOT BUILD_RELEASE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git/" )
|
||||||
# if Qt5 isn't available but Qt6 is. This also saves messing around
|
include( CMakeDateStamp )
|
||||||
# with special CMake flags for every script (e.g. ci/RELEASE.sh and
|
set( CALAMARES_VERSION_DATE "${CMAKE_DATESTAMP_YEAR}${CMAKE_DATESTAMP_MONTH}${CMAKE_DATESTAMP_DAY}" )
|
||||||
# ci/abicheck.sh).
|
if( CALAMARES_VERSION_DATE GREATER 0 )
|
||||||
if(NOT WITH_QT6)
|
set( CALAMARES_VERSION ${CALAMARES_VERSION}.${CALAMARES_VERSION_DATE} )
|
||||||
find_package(Qt5Core QUIET)
|
|
||||||
if(NOT TARGET Qt5::Core)
|
|
||||||
find_package(Qt6Core QUIET)
|
|
||||||
if(TARGET Qt6::Core)
|
|
||||||
message(STATUS "Default Qt version (Qt5) not found, upgrading build to Qt6")
|
|
||||||
set(WITH_QT6 ON)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
|
||||||
if(WITH_QT6)
|
|
||||||
message(STATUS "Building Calamares with Qt6")
|
|
||||||
set(qtname "Qt6")
|
|
||||||
set(kfname "KF6")
|
|
||||||
set(QT_VERSION 6.5.0)
|
|
||||||
set(ECM_VERSION 5.240)
|
|
||||||
set(KF_VERSION 5.240) # KDE Neon weirdness
|
|
||||||
# API that was deprecated before Qt 5.15 causes a compile error
|
|
||||||
add_compile_definitions(QT_DISABLE_DEPRECATED_BEFORE=0x060400)
|
|
||||||
# Something to add to filenames for this specific Qt version
|
|
||||||
set(QT_VERSION_SUFFIX "-qt6")
|
|
||||||
else()
|
|
||||||
message(STATUS "Building Calamares with Qt5")
|
|
||||||
set(qtname "Qt5")
|
|
||||||
set(kfname "KF5")
|
|
||||||
set(QT_VERSION 5.15.0)
|
|
||||||
set(ECM_VERSION 5.78)
|
|
||||||
set(KF_VERSION 5.78)
|
|
||||||
# API that was deprecated before Qt 5.15 causes a compile error
|
|
||||||
add_compile_definitions(QT_DISABLE_DEPRECATED_BEFORE=0x050f00)
|
|
||||||
# Something to add to filenames for this specific Qt version
|
|
||||||
set(QT_VERSION_SUFFIX "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(BOOSTPYTHON_VERSION 1.72.0)
|
include( CMakeVersionSource )
|
||||||
if(DEFINED PYTHONLIBS_VERSION)
|
if( CMAKE_VERSION_SOURCE )
|
||||||
set(PYTHONLIBS_EXTRA "EXACT")
|
set( CALAMARES_VERSION ${CALAMARES_VERSION}-${CMAKE_VERSION_SOURCE} )
|
||||||
else()
|
|
||||||
set(PYTHONLIBS_VERSION 3.6)
|
|
||||||
set(PYTHONLIBS_EXTRA "")
|
|
||||||
endif()
|
|
||||||
set(YAMLCPP_VERSION 0.5.1)
|
|
||||||
|
|
||||||
### CMAKE SETUP
|
|
||||||
#
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules")
|
|
||||||
|
|
||||||
# Enable IN_LIST
|
|
||||||
cmake_policy(SET CMP0057 NEW)
|
|
||||||
# Let ``AUTOMOC`` and ``AUTOUIC`` process ``GENERATED`` files.
|
|
||||||
cmake_policy(SET CMP0071 NEW)
|
|
||||||
# Recognize more macros to trigger automoc
|
|
||||||
list(APPEND CMAKE_AUTOMOC_MACRO_NAMES
|
|
||||||
"K_PLUGIN_FACTORY_WITH_JSON"
|
|
||||||
"K_EXPORT_PLASMA_DATAENGINE_WITH_JSON"
|
|
||||||
"K_EXPORT_PLASMA_RUNNER"
|
|
||||||
)
|
|
||||||
if(POLICY CMP0171)
|
|
||||||
cmake_policy(SET CMP0177 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CMake Modules
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
include(CTest)
|
|
||||||
include(FeatureSummary)
|
|
||||||
|
|
||||||
# Calamares Modules
|
|
||||||
include(CMakeColors)
|
|
||||||
|
|
||||||
### C++ SETUP
|
|
||||||
#
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror=return-type")
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g ${CMAKE_CXX_FLAGS_DEBUG}")
|
|
||||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
|
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "-Og -g")
|
|
||||||
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
|
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
|
|
||||||
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined -Wl,--fatal-warnings ${CMAKE_SHARED_LINKER_FLAGS}")
|
|
||||||
|
|
||||||
# If no build type is set, pick a reasonable one
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
|
||||||
if(CALAMARES_RELEASE_MODE)
|
|
||||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
|
|
||||||
else()
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
||||||
message(STATUS "Found Clang ${CMAKE_CXX_COMPILER_VERSION}, setting up Clang-specific compiler flags.")
|
|
||||||
|
|
||||||
# Clang warnings: doing *everything* is counter-productive, since it warns
|
|
||||||
# about things which we can't fix (e.g. C++98 incompatibilities, but
|
|
||||||
# Calamares is C++17).
|
|
||||||
foreach(
|
|
||||||
CLANG_WARNINGS
|
|
||||||
-Weverything
|
|
||||||
-Wno-c++98-compat
|
|
||||||
-Wno-c++98-compat-pedantic
|
|
||||||
-Wno-padded
|
|
||||||
-Wno-undefined-reinterpret-cast
|
|
||||||
-Wno-global-constructors
|
|
||||||
-Wno-exit-time-destructors
|
|
||||||
-Wno-missing-prototypes
|
|
||||||
-Wno-documentation-unknown-command
|
|
||||||
-Wno-unknown-warning-option
|
|
||||||
)
|
|
||||||
string(APPEND CMAKE_CXX_FLAGS " ${CLANG_WARNINGS}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# The dwarf-debugging flags are slightly different, too
|
|
||||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -gdwarf")
|
|
||||||
string(APPEND CMAKE_C_FLAGS_DEBUG " -gdwarf")
|
|
||||||
|
|
||||||
# Third-party code where we don't care so much about compiler warnings
|
|
||||||
# (because it's uncomfortable to patch) get different flags; use
|
|
||||||
# mark_thirdparty_code( <file> [<file>...] )
|
|
||||||
# to switch off warnings for those sources.
|
|
||||||
set(SUPPRESS_3RDPARTY_WARNINGS "-Wno-everything")
|
|
||||||
|
|
||||||
set(CMAKE_TOOLCHAIN_PREFIX "llvm-")
|
|
||||||
|
|
||||||
# The path prefix is only relevant for CMake 3.16 and later, fixes #1286
|
|
||||||
set(CMAKE_AUTOMOC_PATH_PREFIX OFF)
|
|
||||||
set(CALAMARES_AUTOMOC_OPTIONS "-butils/moc-warnings.h")
|
|
||||||
set(CALAMARES_AUTOUIC_OPTIONS --include utils/moc-warnings.h)
|
|
||||||
else()
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Woverloaded-virtual")
|
|
||||||
|
|
||||||
set(SUPPRESS_3RDPARTY_WARNINGS "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Use mark_thirdparty_code() to reduce warnings from the compiler
|
|
||||||
# on code that we're not going to fix. Call this with a list of files.
|
|
||||||
macro(mark_thirdparty_code)
|
|
||||||
set_source_files_properties(
|
|
||||||
${ARGV}
|
|
||||||
PROPERTIES COMPILE_FLAGS "${SUPPRESS_3RDPARTY_WARNINGS}" COMPILE_DEFINITIONS "THIRDPARTY"
|
|
||||||
)
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.9)
|
|
||||||
message(STATUS "Found GNU g++ ${CMAKE_CXX_COMPILER_VERSION}, enabling colorized error messages.")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=auto")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
### DEPENDENCIES
|
|
||||||
#
|
|
||||||
find_package(${qtname} ${QT_VERSION} CONFIG REQUIRED Concurrent Core DBus Gui LinguistTools Network Svg Widgets)
|
|
||||||
if(WITH_QML)
|
|
||||||
find_package(${qtname} ${QT_VERSION} CONFIG REQUIRED Quick QuickWidgets)
|
|
||||||
endif()
|
|
||||||
# Note that some modules need more Qt modules, optionally.
|
|
||||||
|
|
||||||
find_package(YAMLCPP ${YAMLCPP_VERSION})
|
|
||||||
set_package_properties(
|
|
||||||
YAMLCPP
|
|
||||||
PROPERTIES
|
|
||||||
TYPE REQUIRED
|
|
||||||
DESCRIPTION "YAML parser for C++"
|
|
||||||
PURPOSE "Parsing of configuration files"
|
|
||||||
)
|
|
||||||
|
|
||||||
find_package(Polkit${qtname}-1)
|
|
||||||
if(INSTALL_POLKIT)
|
|
||||||
set_package_properties(
|
|
||||||
Polkit${qtname}-1
|
|
||||||
PROPERTIES
|
|
||||||
TYPE REQUIRED
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
set_package_properties(
|
|
||||||
Polkit${qtname}-1
|
|
||||||
PROPERTIES
|
|
||||||
DESCRIPTION "${qtname} support for Polkit"
|
|
||||||
URL "https://cgit.kde.org/polkit-qt-1.git"
|
|
||||||
PURPOSE "Polkit${qtname}-1 helps with installing Polkit configuration"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Find ECM once, and add it to the module search path; Calamares
|
|
||||||
# modules that need ECM can do
|
|
||||||
# if(ECM_FOUND)
|
|
||||||
# no need to mess with the module path after.
|
|
||||||
find_package(ECM ${ECM_VERSION} NO_MODULE)
|
|
||||||
if(ECM_FOUND)
|
|
||||||
message(STATUS "Found KDE ECM ${ECM_MODULE_PATH}")
|
|
||||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
# ECM implies that we can build the tests, too
|
|
||||||
find_package(${qtname} COMPONENTS Test REQUIRED)
|
|
||||||
include(ECMAddTests)
|
|
||||||
endif()
|
|
||||||
include(KDEInstallDirs)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(${kfname}CoreAddons ${KF_VERSION} QUIET)
|
|
||||||
set_package_properties(
|
|
||||||
${kfname}CoreAddons
|
|
||||||
PROPERTIES
|
|
||||||
TYPE REQUIRED
|
|
||||||
DESCRIPTION "KDE Framework CoreAddons"
|
|
||||||
URL "https://api.kde.org/frameworks/"
|
|
||||||
PURPOSE "Essential Framework for AboutData and Macros"
|
|
||||||
)
|
|
||||||
|
|
||||||
# After this point, there should be no REQUIRED find_packages,
|
|
||||||
# since we want tidy reporting of optional dependencies.
|
|
||||||
feature_summary(
|
|
||||||
WHAT REQUIRED_PACKAGES_NOT_FOUND
|
|
||||||
FATAL_ON_MISSING_REQUIRED_PACKAGES
|
|
||||||
DESCRIPTION "The following REQUIRED packages were not found:"
|
|
||||||
QUIET_ON_EMPTY
|
|
||||||
)
|
|
||||||
|
|
||||||
#
|
|
||||||
# OPTIONAL DEPENDENCIES
|
|
||||||
#
|
|
||||||
# First, set KF back to optional so that any missing components don't trip us up.
|
|
||||||
find_package(${kfname}Crash ${KF_VERSION} QUIET)
|
|
||||||
set_package_properties(
|
|
||||||
${kfname}Crash
|
|
||||||
PROPERTIES
|
|
||||||
TYPE OPTIONAL
|
|
||||||
DESCRIPTION "KDE Framework Crash"
|
|
||||||
URL "https://api.kde.org/frameworks/"
|
|
||||||
PURPOSE "Framework for sending Crash Dumps"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT TARGET ${kfname}::Crash)
|
|
||||||
if(BUILD_CRASH_REPORTING)
|
|
||||||
message(WARNING "BUILD_CRASH_REPORTING is set, but ${kfname}::Crash is not available.")
|
|
||||||
endif()
|
|
||||||
set(BUILD_CRASH_REPORTING OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Python ${PYTHONLIBS_VERSION} ${PYTHONLIBS_EXTRA} COMPONENTS Interpreter Development)
|
|
||||||
set_package_properties(
|
|
||||||
Python
|
|
||||||
PROPERTIES
|
|
||||||
DESCRIPTION "Python3 interpreter."
|
|
||||||
URL "https://python.org"
|
|
||||||
PURPOSE "Python3 interpreter for certain tests."
|
|
||||||
)
|
|
||||||
|
|
||||||
set(_schema_explanation "")
|
|
||||||
if(Python_Interpreter_FOUND)
|
|
||||||
if(BUILD_SCHEMA_TESTING)
|
|
||||||
# The configuration validator script has some dependencies,
|
|
||||||
# and if they are not installed, don't run. If errors out
|
|
||||||
# with exit(1) on missing dependencies.
|
|
||||||
if(CALAMARES_CONFIGVALIDATOR_CHECKED)
|
|
||||||
message(STATUS "Using cached config-validation result")
|
|
||||||
set(_validator_deps ${CALAMARES_CONFIGVALIDATOR_RESULT})
|
|
||||||
else()
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${Python_EXECUTABLE} "${CMAKE_SOURCE_DIR}/ci/configvalidator.py" -x
|
|
||||||
RESULT_VARIABLE _validator_deps
|
|
||||||
)
|
|
||||||
set(CALAMARES_CONFIGVALIDATOR_CHECKED TRUE CACHE INTERNAL "Dependencies for configvalidator checked")
|
|
||||||
set(CALAMARES_CONFIGVALIDATOR_RESULT ${_validator_deps}
|
|
||||||
CACHE INTERNAL "Result of configvalidator dependency check"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
# It should never succeed, but only returns 1 when the imports fail
|
|
||||||
if(_validator_deps EQUAL 1)
|
|
||||||
message(STATUS "Checked for config-validation dependencies: NOT-FOUND")
|
|
||||||
set(_schema_explanation " Missing dependencies for configvalidator.py.")
|
|
||||||
set(BUILD_SCHEMA_TESTING OFF)
|
|
||||||
else()
|
|
||||||
message(STATUS "Checked for config-validation dependencies: found")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(CALAMARES_CONFIGVALIDATOR_CHECKED OFF CACHE INTERNAL "Dependencies for configvalidator checked")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
# Can't run schema tests without Python3.
|
|
||||||
set(_schema_explanation " Missing Python3.")
|
|
||||||
set(BUILD_SCHEMA_TESTING OFF)
|
|
||||||
set(CALAMARES_CONFIGVALIDATOR_CHECKED OFF CACHE INTERNAL "Dependencies for configvalidator checked")
|
|
||||||
endif()
|
|
||||||
add_feature_info(yaml-schema BUILD_SCHEMA_TESTING "Validate YAML (config files) with schema.${_schema_explanation}")
|
|
||||||
|
|
||||||
if(NOT Python_Development_FOUND)
|
|
||||||
message(STATUS "Disabling Python modules")
|
|
||||||
set(WITH_PYTHON OFF)
|
|
||||||
set(WITH_PYBIND11 OFF)
|
|
||||||
set(WITH_BOOST_PYTHON OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_PYTHON AND NOT WITH_PYBIND11)
|
|
||||||
set(WITH_BOOST_PYTHON ON)
|
|
||||||
find_package(boost_python)
|
|
||||||
if(NOT TARGET Boost::python)
|
|
||||||
find_package(Boost ${BOOSTPYTHON_VERSION} COMPONENTS python)
|
|
||||||
set_package_properties(Boost PROPERTIES
|
|
||||||
PURPOSE "Boost.Python is used for Python job modules (because WITH_PYBIND11 is OFF)."
|
|
||||||
TYPE REQUIRED
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
message(STATUS "Found boost_python with target Boost::python")
|
|
||||||
set(Boost_FOUND ON)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
add_feature_info(python WITH_PYTHON "Enable Python-modules")
|
|
||||||
add_feature_info(python-pybind11 WITH_PYBIND11 "Python-modules through pybind11")
|
|
||||||
add_feature_info(python-boost WITH_BOOST_PYTHON "Python-modules through Boost::Python")
|
|
||||||
|
|
||||||
# Now we know the state of the ABI-options, copy them into "Calamares_"
|
|
||||||
# prefixed variables, to match how the variables would-be-named
|
|
||||||
# when building out-of-tree.
|
|
||||||
set(Calamares_WITH_PYTHON ${WITH_PYTHON})
|
|
||||||
set(Calamares_WITH_PYBIND11 ${WITH_PYBIND11})
|
|
||||||
set(Calamares_WITH_BOOST_PYTHON ${WITH_BOOST_PYTHON})
|
|
||||||
set(Calamares_WITH_QML ${WITH_QML})
|
|
||||||
set(Calamares_WITH_QT6 ${WITH_QT6})
|
|
||||||
|
|
||||||
### Transifex Translation status
|
|
||||||
#
|
|
||||||
# Construct language lists for use. This massages the language lists if
|
|
||||||
# needed and checks for some obvious errors. The actual work of
|
|
||||||
# compiling translations is done in the lang/ directory.
|
|
||||||
#
|
|
||||||
|
|
||||||
set(curr_tx ${_tx_complete} ${_tx_good} ${_tx_ok} ${_tx_incomplete})
|
|
||||||
set(tx_errors OFF)
|
|
||||||
if(curr_tx)
|
|
||||||
# New in list
|
|
||||||
foreach(l ${curr_tx})
|
|
||||||
set(p_l "lang/calamares_${l}.ts")
|
|
||||||
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${p_l})
|
|
||||||
message(WARNING "Language ${l} has no .ts file yet.")
|
|
||||||
set(tx_errors ON)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
unset(p_l)
|
|
||||||
unset(l)
|
|
||||||
endif()
|
|
||||||
unset(curr_tx)
|
|
||||||
if(tx_errors)
|
|
||||||
message(FATAL_ERROR "Translation warnings, see above.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CALAMARES_TRANSLATION_LANGUAGES en ${_tx_complete} ${_tx_good} ${_tx_ok})
|
|
||||||
if(NOT CALAMARES_RELEASE_MODE)
|
|
||||||
# Outside of release mode, enable all the languages
|
|
||||||
list(APPEND CALAMARES_TRANSLATION_LANGUAGES ${_tx_incomplete})
|
|
||||||
endif()
|
|
||||||
list(SORT CALAMARES_TRANSLATION_LANGUAGES)
|
|
||||||
list(REMOVE_DUPLICATES CALAMARES_TRANSLATION_LANGUAGES)
|
|
||||||
|
|
||||||
add_subdirectory(lang) # i18n tools
|
|
||||||
|
|
||||||
### Example Distro
|
|
||||||
#
|
|
||||||
# For testing purposes Calamares includes a very, very, limited sample
|
|
||||||
# distro called "Generic". The root filesystem of "Generic" lives in
|
|
||||||
# data/example-root and can be squashed up as part of the build, so
|
|
||||||
# that a pure-upstream run of ./calamares -d from the build directory
|
|
||||||
# (with all the default settings and configurations) can actually
|
|
||||||
# do an complete example run.
|
|
||||||
#
|
|
||||||
# Some binaries from the build host (e.g. /bin and /lib) are also
|
|
||||||
# squashed into the example filesystem.
|
|
||||||
#
|
|
||||||
# To build the example distro (for use by the default, example,
|
|
||||||
# unsquashfs module), build the target 'example-distro', eg.:
|
|
||||||
#
|
|
||||||
# make example-distro
|
|
||||||
#
|
|
||||||
find_program(mksquashfs_PROGRAM mksquashfs)
|
|
||||||
if(mksquashfs_PROGRAM)
|
|
||||||
set(mksquashfs_FOUND ON)
|
|
||||||
set(src_fs ${CMAKE_SOURCE_DIR}/data/example-root/)
|
|
||||||
set(dst_fs ${CMAKE_BINARY_DIR}/example.sqfs)
|
|
||||||
if(EXISTS ${src_fs})
|
|
||||||
# based on the build host. If /lib64 exists, assume it is needed.
|
|
||||||
# Collect directories needed for a minimal binary distro,
|
|
||||||
# Note that the last path component is added to the root, so
|
|
||||||
# if you add /usr/sbin here, it will be put into /sbin_1.
|
|
||||||
# Add such paths to /etc/profile under ${src_fs}.
|
|
||||||
set(candidate_fs /sbin /bin /lib /lib64)
|
|
||||||
set(host_fs "")
|
|
||||||
foreach(c_fs ${candidate_fs})
|
|
||||||
if(EXISTS ${c_fs})
|
|
||||||
list(APPEND host_fs ${c_fs})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${dst_fs}
|
|
||||||
COMMAND ${mksquashfs_PROGRAM} ${src_fs} ${dst_fs} -all-root
|
|
||||||
COMMAND ${mksquashfs_PROGRAM} ${host_fs} ${dst_fs} -all-root
|
|
||||||
)
|
|
||||||
add_custom_target(example-distro DEPENDS ${dst_fs})
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(mksquashfs_FOUND OFF)
|
|
||||||
endif()
|
|
||||||
# Doesn't list mksquashfs as an optional dep, though, because it
|
|
||||||
# hasn't been sent through the find_package() scheme.
|
|
||||||
#
|
|
||||||
# "http://tldp.org/HOWTO/SquashFS-HOWTO/creatingandusing.html"
|
|
||||||
add_feature_info(ExampleDistro ${mksquashfs_FOUND} "Create example-distro target.")
|
|
||||||
|
|
||||||
### CALAMARES PROPER
|
|
||||||
#
|
|
||||||
|
|
||||||
# Additional info for non-release builds. The "extended" version information
|
|
||||||
# with date and git information (commit, dirty status) is used only
|
|
||||||
# by CalamaresVersionX.h, which is included by consumers that need a full
|
|
||||||
# version number with all that information; normal consumers can include
|
|
||||||
# CalamaresVersion.h with more stable numbers.
|
|
||||||
if(NOT CALAMARES_RELEASE_MODE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git/")
|
|
||||||
include(ExtendedVersion)
|
|
||||||
extend_version( "${CALAMARES_VERSION}" OFF CALAMARES_VERSION_SHORT CALAMARES_VERSION_LONG )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Special define for RC (e.g. not-a-release) builds.
|
|
||||||
# This is consumed via the CalamaresConfig.h header.
|
|
||||||
if(NOT CALAMARES_RELEASE_MODE)
|
|
||||||
set(CALAMARES_VERSION_RC 1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# enforce using constBegin, constEnd for const-iterators
|
# enforce using constBegin, constEnd for const-iterators
|
||||||
add_definitions(-DQT_STRICT_ITERATORS -DQT_SHARED -DQT_SHAREDPOINTER_TRACK_POINTERS)
|
add_definitions( "-DQT_STRICT_ITERATORS" )
|
||||||
|
|
||||||
# set paths
|
# set paths
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" )
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" )
|
||||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" )
|
||||||
|
|
||||||
# Better default installation paths: GNUInstallDirs defines
|
# Better default installation paths: GNUInstallDirs defines
|
||||||
# CMAKE_INSTALL_FULL_SYSCONFDIR to be CMAKE_INSTALL_PREFIX/etc by default
|
# CMAKE_INSTALL_FULL_SYSCONFDIR to be CMAKE_INSTALL_PREFIX/etc by default
|
||||||
# but we really want /etc
|
# but we really want /etc
|
||||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
if( NOT DEFINED CMAKE_INSTALL_SYSCONFDIR )
|
||||||
set(CMAKE_INSTALL_SYSCONFDIR "/etc")
|
set( CMAKE_INSTALL_SYSCONFDIR "/etc" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# make predefined install dirs available everywhere
|
# make predefined install dirs available everywhere
|
||||||
include(GNUInstallDirs)
|
include( GNUInstallDirs )
|
||||||
|
|
||||||
# This is used by CalamaresAddLibrary; once Calamares is installed,
|
# make uninstall support
|
||||||
# the CalamaresConfig.cmake module sets this variable to the IMPORTED
|
configure_file(
|
||||||
# libraries for Calamares.
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||||
set(Calamares_LIBRARIES calamares)
|
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||||
|
IMMEDIATE @ONLY
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(3rdparty/kdsingleapplication)
|
# Early configure these files as we need them later on
|
||||||
if(WITH_PYBIND11)
|
configure_file( CalamaresUse.cmake.in "${PROJECT_BINARY_DIR}/CalamaresUse.cmake" @ONLY )
|
||||||
add_subdirectory(3rdparty/pybind11)
|
file( COPY CalamaresAddLibrary.cmake DESTINATION "${PROJECT_BINARY_DIR}" )
|
||||||
|
file( COPY CalamaresAddModuleSubdirectory.cmake DESTINATION "${PROJECT_BINARY_DIR}" )
|
||||||
|
file( COPY CalamaresAddPlugin.cmake DESTINATION "${PROJECT_BINARY_DIR}" )
|
||||||
|
file( COPY CalamaresAddBrandingSubdirectory.cmake DESTINATION "${PROJECT_BINARY_DIR}" )
|
||||||
|
|
||||||
|
set( CALAMARES_LIBRARIES calamares )
|
||||||
|
|
||||||
|
set( THIRDPARTY_DIR "${CMAKE_SOURCE_DIR}/thirdparty" )
|
||||||
|
|
||||||
|
add_subdirectory( thirdparty )
|
||||||
|
add_subdirectory( src )
|
||||||
|
|
||||||
|
macro_display_feature_log()
|
||||||
|
|
||||||
|
if ( NOT WITH_PYTHON )
|
||||||
|
message( "-- WARNING: Building Calamares without Python support. Legacy Python job modules will not work.\n" )
|
||||||
|
endif()
|
||||||
|
if ( NOT WITH_PYTHONQT )
|
||||||
|
message( "-- WARNING: Building Calamares without PythonQt support. Python modules will not work.\n" )
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(src)
|
|
||||||
|
|
||||||
add_feature_info(Python ${WITH_PYTHON} "Python job modules")
|
|
||||||
add_feature_info(Pybind11 ${WITH_PYBIND11} "Python using bundled pybind11")
|
|
||||||
add_feature_info(Qml ${WITH_QML} "QML UI support")
|
|
||||||
add_feature_info(Polkit ${INSTALL_POLKIT} "Install Polkit files")
|
|
||||||
add_feature_info(KCrash ${BUILD_CRASH_REPORTING} "Crash dumps via KCrash")
|
|
||||||
|
|
||||||
### Post-source configuration
|
if ( NOT INSTALL_CONFIG )
|
||||||
#
|
message( "-- WARNING: Configuration files will not be installed.\n" )
|
||||||
#
|
endif()
|
||||||
find_package(${kfname} ${KF_VERSION} QUIET COMPONENTS CoreAddons)
|
|
||||||
|
|
||||||
### CMake infrastructure installation
|
# Add all targets to the build-tree export set
|
||||||
#
|
set( CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/Calamares" CACHE PATH "Installation directory for CMake files" )
|
||||||
#
|
set( CMAKE_INSTALL_FULL_CMAKEDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}" )
|
||||||
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/Calamares" CACHE PATH "Installation directory for CMake files")
|
export( TARGETS calamares
|
||||||
set(CMAKE_INSTALL_FULL_CMAKEDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_CMAKEDIR}")
|
FILE "${PROJECT_BINARY_DIR}/CalamaresLibraryDepends.cmake" )
|
||||||
|
|
||||||
export(PACKAGE Calamares)
|
# Export the package for use from the build-tree
|
||||||
configure_package_config_file(
|
# (this registers the build-tree with a global CMake-registry)
|
||||||
"CalamaresConfig.cmake.in"
|
export( PACKAGE Calamares )
|
||||||
"${PROJECT_BINARY_DIR}/CalamaresConfig.cmake"
|
|
||||||
INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
|
# Create a CalamaresBuildTreeSettings.cmake file for the use from the build tree
|
||||||
PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_DATADIR
|
configure_file( CalamaresBuildTreeSettings.cmake.in "${PROJECT_BINARY_DIR}/CalamaresBuildTreeSettings.cmake" @ONLY )
|
||||||
)
|
|
||||||
write_basic_package_version_file(
|
# Create the CalamaresConfig.cmake and CalamaresConfigVersion files
|
||||||
${PROJECT_BINARY_DIR}/CalamaresConfigVersion.cmake
|
file( RELATIVE_PATH CONF_REL_INCLUDE_DIR "${CMAKE_INSTALL_FULL_CMAKEDIR}" "${CMAKE_INSTALL_FULL_INCLUDEDIR}" )
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
COMPATIBILITY SameMajorVersion
|
configure_file( CalamaresConfig.cmake.in "${PROJECT_BINARY_DIR}/CalamaresConfig.cmake" @ONLY )
|
||||||
)
|
configure_file( CalamaresConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/CalamaresConfigVersion.cmake" @ONLY )
|
||||||
install(EXPORT Calamares DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" FILE "CalamaresTargets.cmake" NAMESPACE Calamares::)
|
|
||||||
|
|
||||||
# Install the cmake files
|
# Install the cmake files
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
"${PROJECT_BINARY_DIR}/CalamaresConfig.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresConfig.cmake"
|
||||||
"${PROJECT_BINARY_DIR}/CalamaresConfigVersion.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresConfigVersion.cmake"
|
||||||
"CMakeModules/CalamaresAddBrandingSubdirectory.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresUse.cmake"
|
||||||
"CMakeModules/CalamaresAddLibrary.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresAddPlugin.cmake"
|
||||||
"CMakeModules/CalamaresAddModuleSubdirectory.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresAddModuleSubdirectory.cmake"
|
||||||
"CMakeModules/CalamaresAddPlugin.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresAddLibrary.cmake"
|
||||||
"CMakeModules/CalamaresAddTest.cmake"
|
"${PROJECT_BINARY_DIR}/CalamaresAddBrandingSubdirectory.cmake"
|
||||||
"CMakeModules/CalamaresAddTranslations.cmake"
|
DESTINATION
|
||||||
"CMakeModules/CalamaresAutomoc.cmake"
|
"${CMAKE_INSTALL_CMAKEDIR}"
|
||||||
"CMakeModules/CalamaresCheckModuleSelection.cmake"
|
|
||||||
"CMakeModules/CMakeColors.cmake"
|
|
||||||
"CMakeModules/FindYAMLCPP.cmake"
|
|
||||||
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
### Miscellaneous installs
|
# Install the export set for use with the install-tree
|
||||||
#
|
install(
|
||||||
#
|
EXPORT
|
||||||
if(INSTALL_POLKIT)
|
CalamaresLibraryDepends
|
||||||
install(FILES com.github.calamares.calamares.policy DESTINATION "${POLKITQT-1_POLICY_FILES_INSTALL_DIR}")
|
DESTINATION
|
||||||
|
"${CMAKE_INSTALL_CMAKEDIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (INSTALL_CONFIG)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
settings.conf
|
||||||
|
DESTINATION
|
||||||
|
share/calamares
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(INSTALL_COMPLETION)
|
install(
|
||||||
if(NOT CMAKE_INSTALL_BASHCOMPLETIONDIR)
|
FILES
|
||||||
set(CMAKE_INSTALL_BASHCOMPLETIONDIR "${CMAKE_INSTALL_DATADIR}/bash-completion/completions")
|
com.github.calamares.calamares.policy
|
||||||
endif()
|
DESTINATION
|
||||||
|
"${POLKITQT-1_POLICY_FILES_INSTALL_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/data/completion/bash/calamares DESTINATION "${CMAKE_INSTALL_BASHCOMPLETIONDIR}")
|
install(
|
||||||
endif()
|
FILES
|
||||||
|
calamares.desktop
|
||||||
|
DESTINATION
|
||||||
|
${CMAKE_INSTALL_DATADIR}/applications
|
||||||
|
)
|
||||||
|
|
||||||
install(FILES calamares.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
# uninstall target
|
||||||
|
|
||||||
install(FILES man/calamares.8 DESTINATION ${CMAKE_INSTALL_MANDIR}/man8/)
|
|
||||||
|
|
||||||
if(INSTALL_CONFIG)
|
|
||||||
install(FILES settings.conf DESTINATION share/calamares)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
### Uninstall
|
|
||||||
#
|
|
||||||
#
|
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||||
IMMEDIATE
|
IMMEDIATE @ONLY
|
||||||
@ONLY
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
add_custom_target( uninstall
|
||||||
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||||
### Developer convenience
|
|
||||||
#
|
|
||||||
# The module support files -- .desc files, .conf files -- are copied into the build
|
|
||||||
# directory so that it is possible to run `calamares -d` from there. Copy the
|
|
||||||
# top-level settings.conf as well, into the build directory.
|
|
||||||
if(settings.conf IS_NEWER_THAN ${CMAKE_BINARY_DIR}/settings.conf)
|
|
||||||
configure_file(settings.conf ${CMAKE_BINARY_DIR}/settings.conf COPYONLY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### CMAKE SUMMARY REPORT
|
|
||||||
#
|
|
||||||
get_directory_property(SKIPPED_MODULES DIRECTORY src/modules DEFINITION LIST_SKIPPED_MODULES)
|
|
||||||
calamares_explain_skipped_modules( ${SKIPPED_MODULES} )
|
|
||||||
|
|
||||||
feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "The following features are enabled" QUIET_ON_EMPTY)
|
|
||||||
feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "The following features have been disabled:" QUIET_ON_EMPTY)
|
|
||||||
feature_summary(
|
|
||||||
WHAT OPTIONAL_PACKAGES_NOT_FOUND
|
|
||||||
DESCRIPTION "The following OPTIONAL packages were not found:"
|
|
||||||
QUIET_ON_EMPTY
|
|
||||||
)
|
)
|
||||||
feature_summary(
|
|
||||||
WHAT REQUIRED_PACKAGES_NOT_FOUND
|
|
||||||
FATAL_ON_MISSING_REQUIRED_PACKAGES
|
|
||||||
DESCRIPTION "The following REQUIRED packages were not found:"
|
|
||||||
QUIET_ON_EMPTY
|
|
||||||
)
|
|
||||||
|
|
||||||
### PACKAGING
|
|
||||||
#
|
|
||||||
# Note: most distro's will do distro-specific packaging rather than
|
|
||||||
# using CPack, and this duplicates information in the AppStream, too.
|
|
||||||
set(CPACK_PACKAGE_VENDOR calamares)
|
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A Linux system installer")
|
|
||||||
set(CPACK_PACKAGE_DESCRIPTION
|
|
||||||
"Calamares is a Linux system installer, intended for Linux distributions to use on their ISOs and other bootable media to install the distribution to the end-user's computer. Calamares can also be used as an OEM configuration tool. It is modular, extensible and highly-configurable for Linux distributions from all five major Linux families."
|
|
||||||
)
|
|
||||||
set(CPACK_PACKAGE_ICON "data/images/squid.png")
|
|
||||||
|
|
||||||
include(CPack)
|
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2023 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Finds AppStream-Qt suitable for the Qt version that is in use.
|
|
||||||
# Creates target calamares::appstreamqt to alias whatever is found.
|
|
||||||
# Sets AppStreamQt_FOUND appropriately, regardless of the underlying
|
|
||||||
# variables (e.g. might be AppStreamQt6_FOUND).
|
|
||||||
#
|
|
||||||
|
|
||||||
option(BUILD_APPSTREAM "Support appstream: items in PackageChooser (requires libappstream-qt)" OFF)
|
|
||||||
|
|
||||||
if(TARGET calaappstream)
|
|
||||||
if(TARGET calamares::appstreamqt)
|
|
||||||
message(STATUS "AppStreamQt has already been found")
|
|
||||||
set(AppStreamQt_FOUND TRUE)
|
|
||||||
else()
|
|
||||||
message(STATUS "AppStreamQt has been searched-for and not found")
|
|
||||||
set(AppStreamQt_FOUND FALSE)
|
|
||||||
endif()
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
if(NOT BUILD_APPSTREAM)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
### FIND APPSTREAM
|
|
||||||
#
|
|
||||||
# First, look for a Qt-versioned variety of the package.
|
|
||||||
# If that is not found, look for an unversioned one.
|
|
||||||
set(HAVE_APPSTREAM OFF)
|
|
||||||
find_package(AppStream${qtname})
|
|
||||||
# Not everyone renames the variables consistently
|
|
||||||
if(AppStream${qtname}_FOUND OR AppStreamQt_FOUND)
|
|
||||||
set(_appstream_name AppStream${qtname})
|
|
||||||
set(HAVE_APPSTREAM ON)
|
|
||||||
else()
|
|
||||||
find_package(AppStreamQt)
|
|
||||||
if(AppStreamQt_FOUND)
|
|
||||||
set(_appstream_name AppStreamQt)
|
|
||||||
# TODO: how to check underlying Qt version?
|
|
||||||
set(HAVE_APPSTREAM ON)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(HAVE_APPSTREAM)
|
|
||||||
# Look for the directory name containing the headers
|
|
||||||
find_file(_appstream_header NAMES ${_appstream_name}/pool.h AppStreamQt/pool.h)
|
|
||||||
if(NOT _appstream_header)
|
|
||||||
set(HAVE_APPSTREAM OFF)
|
|
||||||
else()
|
|
||||||
if(_appstream_header MATCHES /${_appstream_name}/)
|
|
||||||
set(_appstream_header_directory ${_appstream_name})
|
|
||||||
else()
|
|
||||||
set(_appstream_header_directory AppStreamQt)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
# Placeholder name
|
|
||||||
set(_appstream_name AppStreamQt)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(_appstream_dependency_type OPTIONAL)
|
|
||||||
if(BUILD_APPSTREAM)
|
|
||||||
set(_appstream_dependency_type REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_package_properties(
|
|
||||||
${_appstream_name}
|
|
||||||
PROPERTIES
|
|
||||||
DESCRIPTION "Support for AppStream (cache) data"
|
|
||||||
URL "https://github.com/ximion/appstream"
|
|
||||||
PURPOSE "AppStream provides package data"
|
|
||||||
TYPE ${_appstream_dependency_type}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(calaappstream INTERFACE) # Always, but might not be populated
|
|
||||||
if(HAVE_APPSTREAM)
|
|
||||||
target_compile_definitions(calaappstream INTERFACE HAVE_APPSTREAM_VERSION=${${_appstream_name}_VERSION_MAJOR} HAVE_APPSTREAM_HEADERS=${_appstream_header_directory})
|
|
||||||
target_link_libraries(calaappstream INTERFACE ${_appstream_name})
|
|
||||||
add_library(calamares::appstreamqt ALIAS calaappstream)
|
|
||||||
endif()
|
|
||||||
set(AppStreamQt_FOUND ${HAVE_APPSTREAM})
|
|
57
CMakeModules/BoostPython3.cmake
Normal file
57
CMakeModules/BoostPython3.cmake
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# On Ubuntu 14.04, the libboost-python1.54-dev package comes with one library
|
||||||
|
# for each Python version:
|
||||||
|
# libboost_python-py27.so
|
||||||
|
# libboost_python-py33.so
|
||||||
|
# libboost_python-py34.so
|
||||||
|
#
|
||||||
|
# Boost upstream however installs Boost.Python3 libboost_python3.so, which is
|
||||||
|
# what FindBoost.cmake is looking for. It looks for a library named
|
||||||
|
# "libboost_${component}.so".
|
||||||
|
#
|
||||||
|
# On Gentoo instead, the >=dev-libs/boost-1.54 package provides boost library
|
||||||
|
# with a name like:
|
||||||
|
# libboost_python-2.7.so
|
||||||
|
# libboost_python-3.3.so
|
||||||
|
# libboost_python-3.4.so
|
||||||
|
# depending on what python's targets you selected during install
|
||||||
|
#
|
||||||
|
# find_boost_python3() tries to find the package with different component
|
||||||
|
# names. By default it tries "python3", "python-py$suffix" and
|
||||||
|
# "python-$dotsuffix", where suffix is based on the `python_version` argument.
|
||||||
|
# One can supply a custom component name by setting the
|
||||||
|
# `CALAMARES_BOOST_PYTHON3_COMPONENT` variable at CMake time.
|
||||||
|
|
||||||
|
set( CALAMARES_BOOST_PYTHON3_COMPONENT python3 CACHE STRING
|
||||||
|
"Name of the Boost.Python component. If Boost.Python is installed as
|
||||||
|
libboost_python-foo.so then this variable should be set to 'python-foo'."
|
||||||
|
)
|
||||||
|
|
||||||
|
macro( find_boost_python3 boost_version python_version found_var )
|
||||||
|
set( ${found_var} OFF )
|
||||||
|
|
||||||
|
# turns "3.4.123abc" into "34"
|
||||||
|
string( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\..*" "\\1\\2" _fbp_python_short_version ${python_version} )
|
||||||
|
|
||||||
|
foreach( _fbp_name ${CALAMARES_BOOST_PYTHON3_COMPONENT} python-py${_fbp_python_short_version} )
|
||||||
|
find_package( Boost ${boost_version} QUIET COMPONENTS ${_fbp_name} )
|
||||||
|
string( TOUPPER ${_fbp_name} _fbp_uc_name )
|
||||||
|
if( Boost_${_fbp_uc_name}_FOUND )
|
||||||
|
set( ${found_var} ON )
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if (NOT ${found_var})
|
||||||
|
# The following loop changes the searched name for Gentoo based distributions
|
||||||
|
# turns "3.4.123abc" into "3.4"
|
||||||
|
string( REGEX REPLACE "([0-9]+)\\.([0-9]+)\\..*" "\\1.\\2" _fbp_python_short_version ${python_version} )
|
||||||
|
foreach( _fbp_name ${CALAMARES_BOOST_PYTHON3_COMPONENT} python-${_fbp_python_short_version} )
|
||||||
|
find_package( Boost ${boost_version} QUIET COMPONENTS ${_fbp_name} )
|
||||||
|
string( TOUPPER ${_fbp_name} _fbp_uc_name )
|
||||||
|
if( Boost_${_fbp_uc_name}_FOUND )
|
||||||
|
set( ${found_var} ON )
|
||||||
|
break()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
@ -1,27 +1,8 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2014 Kevin Kofler <kevin.kofler@chello.at>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Defines a handful of strings that, with normal xterm handling,
|
|
||||||
# will change colors in the output, so it's nicer to read.
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
set(_use_color ON)
|
# [ -t 2 ] tests whether stderr is interactive.
|
||||||
if("0" STREQUAL "$ENV{CLICOLOR}")
|
# The negation '!' is because for POSIX shells, 0 is true and 1 is false.
|
||||||
set(_use_color OFF)
|
execute_process(COMMAND test ! -t 2 RESULT_VARIABLE IS_STDERR_INTERACTIVE)
|
||||||
endif()
|
if(IS_STDERR_INTERACTIVE)
|
||||||
if("0" STREQUAL "$ENV{CLICOLOR_FORCE}")
|
|
||||||
set(_use_color OFF)
|
|
||||||
endif()
|
|
||||||
if(NOT CMAKE_COLOR_MAKEFILE)
|
|
||||||
set(_use_color OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(_use_color)
|
|
||||||
string(ASCII 27 Esc)
|
string(ASCII 27 Esc)
|
||||||
set(ColorReset "${Esc}[m")
|
set(ColorReset "${Esc}[m")
|
||||||
set(ColorBold "${Esc}[1m")
|
set(ColorBold "${Esc}[1m")
|
||||||
@ -39,5 +20,5 @@ if(NOT WIN32)
|
|||||||
set(BoldMagenta "${Esc}[1;35m")
|
set(BoldMagenta "${Esc}[1;35m")
|
||||||
set(BoldCyan "${Esc}[1;36m")
|
set(BoldCyan "${Esc}[1;36m")
|
||||||
set(BoldWhite "${Esc}[1;37m")
|
set(BoldWhite "${Esc}[1;37m")
|
||||||
endif()
|
endif(IS_STDERR_INTERACTIVE)
|
||||||
endif()
|
endif()
|
||||||
|
23
CMakeModules/CMakeDateStamp.cmake
Normal file
23
CMakeModules/CMakeDateStamp.cmake
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
find_program(DATE_EXECUTABLE NAMES date)
|
||||||
|
mark_as_advanced(DATE_EXECUTABLE)
|
||||||
|
|
||||||
|
if(DATE_EXECUTABLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${DATE_EXECUTABLE} +%Y
|
||||||
|
OUTPUT_VARIABLE CMAKE_DATESTAMP_YEAR
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${DATE_EXECUTABLE} +%m
|
||||||
|
OUTPUT_VARIABLE CMAKE_DATESTAMP_MONTH
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${DATE_EXECUTABLE} +%d
|
||||||
|
OUTPUT_VARIABLE CMAKE_DATESTAMP_DAY
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
endif()
|
45
CMakeModules/CMakeVersionSource.cmake
Normal file
45
CMakeModules/CMakeVersionSource.cmake
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Try to identify the current development source version.
|
||||||
|
set(CMAKE_VERSION_SOURCE "")
|
||||||
|
if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD)
|
||||||
|
find_program(GIT_EXECUTABLE NAMES git git.cmd)
|
||||||
|
mark_as_advanced(GIT_EXECUTABLE)
|
||||||
|
if(GIT_EXECUTABLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=7 HEAD
|
||||||
|
OUTPUT_VARIABLE head
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
if(head)
|
||||||
|
set(branch "")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} name-rev HEAD
|
||||||
|
OUTPUT_VARIABLE branch
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
string(REGEX REPLACE "HEAD " "" branch "${branch}")
|
||||||
|
set(CMAKE_VERSION_SOURCE "git-${branch}-${head}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
|
||||||
|
OUTPUT_VARIABLE dirty
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
if(dirty)
|
||||||
|
set(CMAKE_VERSION_SOURCE "${CMAKE_VERSION_SOURCE}-dirty")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
elseif(EXISTS ${CMAKE_SOURCE_DIR}/CVS/Repository)
|
||||||
|
file(READ ${CMAKE_SOURCE_DIR}/CVS/Repository repo)
|
||||||
|
set(branch "")
|
||||||
|
if("${repo}" MATCHES "\\.git/")
|
||||||
|
string(REGEX REPLACE ".*\\.git/([^\r\n]*).*" "-\\1" branch "${repo}")
|
||||||
|
endif()
|
||||||
|
set(CMAKE_VERSION_SOURCE "cvs${branch}")
|
||||||
|
endif()
|
@ -1,147 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Support macros for creating Calamares branding components.
|
|
||||||
#
|
|
||||||
# Calamares branding components have two parts:
|
|
||||||
# - a branding.desc file that tells Calamares how to describe the product
|
|
||||||
# (e.g. strings like "Generic GNU/Linux") and the name of a QML file
|
|
||||||
# (the "slideshow") that is displayed during installation.
|
|
||||||
# - the QML files themselves, plus supporting images etc.
|
|
||||||
#
|
|
||||||
# Branding components can be created inside the Calamares source tree
|
|
||||||
# (there is one example the `default/` branding, which is also connected
|
|
||||||
# to the default configuration shipped with Calamares), but they can be
|
|
||||||
# built outside of, and largely independently of, Calamares by using
|
|
||||||
# these CMake macros.
|
|
||||||
#
|
|
||||||
# See the calamares-examples repository for more examples.
|
|
||||||
#
|
|
||||||
include( CMakeParseArguments)
|
|
||||||
|
|
||||||
include( CMakeColors )
|
|
||||||
|
|
||||||
# Usage calamares_add_branding( <name> [DIRECTORY <dir>] [SUBDIRECTORIES <dir> ...])
|
|
||||||
#
|
|
||||||
# Adds a branding component to the build:
|
|
||||||
# - the component's top-level files are copied into the build-dir;
|
|
||||||
# CMakeLists.txt is excluded from the glob.
|
|
||||||
# - the component's top-level files are installed into the component branding dir
|
|
||||||
#
|
|
||||||
# The branding component lives in <dir> if given, otherwise the
|
|
||||||
# current source directory. The branding component is installed
|
|
||||||
# with the given <name>, which is usually the name of the
|
|
||||||
# directory containing the component, and which must match the
|
|
||||||
# *componentName* in `branding.desc`.
|
|
||||||
#
|
|
||||||
# If SUBDIRECTORIES are given, then those are copied (each one level deep)
|
|
||||||
# to the installation location as well, preserving the subdirectory name.
|
|
||||||
function( calamares_add_branding NAME )
|
|
||||||
cmake_parse_arguments( _CABT "" "DIRECTORY" "SUBDIRECTORIES" ${ARGN} )
|
|
||||||
if (NOT _CABT_DIRECTORY)
|
|
||||||
set(_CABT_DIRECTORY ".")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( SUBDIRECTORY ${_CABT_DIRECTORY} )
|
|
||||||
set( _brand_dir ${_CABT_DIRECTORY} )
|
|
||||||
|
|
||||||
set( BRANDING_DIR share/calamares/branding )
|
|
||||||
set( BRANDING_COMPONENT_DESTINATION ${BRANDING_DIR}/${NAME} )
|
|
||||||
|
|
||||||
foreach( _subdir "" ${_CABT_SUBDIRECTORIES} )
|
|
||||||
file( GLOB BRANDING_COMPONENT_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${_brand_dir} "${_brand_dir}/${_subdir}/*" )
|
|
||||||
foreach( BRANDING_COMPONENT_FILE ${BRANDING_COMPONENT_FILES} )
|
|
||||||
set( _subpath ${_brand_dir}/${BRANDING_COMPONENT_FILE} )
|
|
||||||
if( NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_subpath} )
|
|
||||||
set( _src ${CMAKE_CURRENT_SOURCE_DIR}/${_subpath} )
|
|
||||||
set( _dst ${CMAKE_CURRENT_BINARY_DIR}/${_subpath} )
|
|
||||||
if( ${_src} IS_NEWER_THAN ${_dst} )
|
|
||||||
configure_file( ${_src} ${_dst} COPYONLY )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${_subpath}
|
|
||||||
DESTINATION ${BRANDING_COMPONENT_DESTINATION}/${_subdir}/ )
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} branding component: ${BoldRed}${NAME}${ColorReset}" )
|
|
||||||
message( " ${Green}TYPE:${ColorReset} branding component" )
|
|
||||||
message( " ${Green}BRANDING_COMPONENT_DESTINATION:${ColorReset} ${BRANDING_COMPONENT_DESTINATION}" )
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Usage calamares_add_branding_translations( <name> [DIRECTORY <dir>])
|
|
||||||
#
|
|
||||||
# Adds the translations for a branding component to the build:
|
|
||||||
# - the component's lang/ directory is scanned for .ts files
|
|
||||||
# - the component's translations are installed into the component branding dir
|
|
||||||
#
|
|
||||||
# Translation files must be called calamares-<name>_<lang>.ts . Optionally
|
|
||||||
# the lang/ dir is found in the given <dir> instead of the current source
|
|
||||||
# directory.
|
|
||||||
function( calamares_add_branding_translations NAME )
|
|
||||||
cmake_parse_arguments( _CABT "" "DIRECTORY" "" ${ARGN} )
|
|
||||||
if (NOT _CABT_DIRECTORY)
|
|
||||||
set(_CABT_DIRECTORY ".")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( SUBDIRECTORY ${_CABT_DIRECTORY} )
|
|
||||||
set( _brand_dir ${_CABT_DIRECTORY} )
|
|
||||||
|
|
||||||
set( BRANDING_DIR share/calamares/branding )
|
|
||||||
set( BRANDING_COMPONENT_DESTINATION ${BRANDING_DIR}/${NAME} )
|
|
||||||
|
|
||||||
file( GLOB BRANDING_TRANSLATION_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${SUBDIRECTORY}/lang/calamares-${NAME}_*.ts" )
|
|
||||||
if ( BRANDING_TRANSLATION_FILES )
|
|
||||||
qt_add_translation( QM_FILES ${BRANDING_TRANSLATION_FILES} )
|
|
||||||
add_custom_target( branding-translation-${NAME} ALL DEPENDS ${QM_FILES}
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/lang/
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${QM_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/lang/
|
|
||||||
)
|
|
||||||
install( FILES ${QM_FILES} DESTINATION ${BRANDING_COMPONENT_DESTINATION}/lang/ )
|
|
||||||
list( LENGTH BRANDING_TRANSLATION_FILES _branding_count )
|
|
||||||
message( " ${Green}BRANDING_TRANSLATIONS:${ColorReset} ${_branding_count} language(s)" )
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Usage calamares_add_branding_subdirectory( <dir> [NAME <name>] [SUBDIRECTORIES <dir> ...])
|
|
||||||
#
|
|
||||||
# Adds a branding component from a subdirectory:
|
|
||||||
# - if there is a CMakeLists.txt, use that (that CMakeLists.txt should
|
|
||||||
# call suitable calamares_add_branding() and other macros to install
|
|
||||||
# the branding component).
|
|
||||||
# - otherwise assume a "standard" setup with top-level files and a lang/
|
|
||||||
# subdirectory for translations.
|
|
||||||
#
|
|
||||||
# If NAME is given, this is used instead of <dir> as the name of
|
|
||||||
# the branding component. This is needed if <dir> is more than
|
|
||||||
# one level deep, or to rename a component as it gets installed.
|
|
||||||
#
|
|
||||||
# If SUBDIRECTORIES are given, they are relative to <dir>, and are
|
|
||||||
# copied (one level deep) to the install location as well.
|
|
||||||
function( calamares_add_branding_subdirectory SUBDIRECTORY )
|
|
||||||
cmake_parse_arguments( _CABS "" "NAME" "SUBDIRECTORIES" ${ARGN} )
|
|
||||||
if (NOT _CABS_NAME)
|
|
||||||
set(_CABS_NAME "${SUBDIRECTORY}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt" )
|
|
||||||
add_subdirectory( ${SUBDIRECTORY} )
|
|
||||||
elseif( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/branding.desc" )
|
|
||||||
calamares_add_branding( ${_CABS_NAME} DIRECTORY ${SUBDIRECTORY} SUBDIRECTORIES ${_CABS_SUBDIRECTORIES} )
|
|
||||||
if( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" )
|
|
||||||
calamares_add_branding_translations( ${_CABS_NAME} DIRECTORY ${SUBDIRECTORY} )
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message( "-- ${BoldYellow}Warning:${ColorReset} tried to add branding component subdirectory ${BoldRed}${SUBDIRECTORY}${ColorReset} which has no branding.desc." )
|
|
||||||
endif()
|
|
||||||
message( "" )
|
|
||||||
endfunction()
|
|
@ -1,287 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Function and support code for adding a Calamares module (either a Qt / C++ plugin,
|
|
||||||
# or a Python module, or whatever) to the build.
|
|
||||||
#
|
|
||||||
# # Usage
|
|
||||||
#
|
|
||||||
# The public API is one single function:
|
|
||||||
#
|
|
||||||
# - calamares_add_module_subdirectory(subdirectory [skiplistvar])
|
|
||||||
# Adds a given *subdirectory* to the modules list, building the
|
|
||||||
# module that is there. The *subdirectory* must contain a `module.desc`
|
|
||||||
# (generally non-C++ modules) or a `CMakeLists.txt` (for C++ modules,
|
|
||||||
# or special cases). The module is assumed to be named after the
|
|
||||||
# (last component of) the subdirectory.
|
|
||||||
#
|
|
||||||
# If the module would be skipped (by the global SKIP_MODULES setting
|
|
||||||
# or a USE_* setting) or the module itself sets a reason to skip
|
|
||||||
# via the calamares_skip_module() function, the module is added to
|
|
||||||
# the list of skipped-modules in *skiplistvar*. If no variable is
|
|
||||||
# given, the reason is set in the parent scope variable
|
|
||||||
# SKIPPED_MODULES . Do **not** use SKIPPED_MODULES as the name of
|
|
||||||
# *skiplistvar*, things will get weird.
|
|
||||||
#
|
|
||||||
# Do note that the name of a module must be the same as the name of
|
|
||||||
# the directory containing it (as documented in src/modules/README.md).
|
|
||||||
# This applies to both C++ and Python modules, and allows the use of
|
|
||||||
# the subdirectory as a proxy for the module name inside.
|
|
||||||
#
|
|
||||||
|
|
||||||
include( CalamaresAddTranslations )
|
|
||||||
include( CalamaresCheckModuleSelection )
|
|
||||||
|
|
||||||
set( MODULE_DATA_DESTINATION share/calamares/modules )
|
|
||||||
|
|
||||||
# We look for Pylint (just once) so that unittests can be added that
|
|
||||||
# check the syntax / variables of Python modules. This should help
|
|
||||||
# avoid more typo's-in-releases.
|
|
||||||
if(BUILD_TESTING AND NOT PYLINT_COMMAND_SEARCHED)
|
|
||||||
set(PYLINT_COMMAND_SEARCHED TRUE)
|
|
||||||
find_program(
|
|
||||||
PYLINT_COMMAND
|
|
||||||
NAMES pylint3 pylint
|
|
||||||
PATHS $ENV{HOME}/.local/bin
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
function( _calamares_add_module_subdirectory_impl )
|
|
||||||
set( SUBDIRECTORY ${ARGV0} )
|
|
||||||
|
|
||||||
# Set SKIPPED_MODULES here, so CMake-based modules have a
|
|
||||||
# parent scope to set it in; this function, in turn sets it
|
|
||||||
# in **its** parent scope.
|
|
||||||
set( SKIPPED_MODULES "" )
|
|
||||||
set( MODULE_CONFIG_FILES "" )
|
|
||||||
|
|
||||||
# The module subdirectory may be given as a/b/c, but the module
|
|
||||||
# needs to be installed as "c", so we split off any intermediate
|
|
||||||
# directories.
|
|
||||||
#
|
|
||||||
# Compute _modulename (the last directory name) and _mod_dir
|
|
||||||
# (the full path to the module sources).
|
|
||||||
get_filename_component(_dirname "${SUBDIRECTORY}" DIRECTORY)
|
|
||||||
if( _dirname )
|
|
||||||
# Remove the dirname and any leftover leading /s
|
|
||||||
string( REGEX REPLACE "^${_dirname}/*" "" _modulename "${SUBDIRECTORY}" )
|
|
||||||
else()
|
|
||||||
set( _modulename ${SUBDIRECTORY} )
|
|
||||||
endif()
|
|
||||||
# Strip any remaining /
|
|
||||||
string( REGEX REPLACE "/" "" _modulename "${_modulename}" )
|
|
||||||
set( _mod_dir "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" )
|
|
||||||
|
|
||||||
# Skip list check applies to all kinds of modules
|
|
||||||
calamares_check_skip( ${_modulename} SKIPPED_MODULES )
|
|
||||||
if ( SKIPPED_MODULES )
|
|
||||||
# If it's skipped by infrastucture, the message already includes the module
|
|
||||||
# name. We don't need to do any further checking.
|
|
||||||
set( SKIPPED_MODULES "${SKIPPED_MODULES}" PARENT_SCOPE )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# If this subdirectory has a CMakeLists.txt, we add_subdirectory it...
|
|
||||||
if( EXISTS "${_mod_dir}/CMakeLists.txt" )
|
|
||||||
add_subdirectory( ${SUBDIRECTORY} )
|
|
||||||
file( GLOB MODULE_CONFIG_FILES RELATIVE ${_mod_dir} "${SUBDIRECTORY}/*.conf" )
|
|
||||||
# Module has indicated it should be skipped, show that in
|
|
||||||
# the calling CMakeLists (which is src/modules/CMakeLists.txt normally).
|
|
||||||
if ( SKIPPED_MODULES )
|
|
||||||
set( SKIPPED_MODULES ${SKIPPED_MODULES} PARENT_SCOPE )
|
|
||||||
set( MODULE_CONFIG_FILES "" )
|
|
||||||
else()
|
|
||||||
# The SKIPPED_MODULES may be set in the directory itself
|
|
||||||
get_directory_property( _skip DIRECTORY ${SUBDIRECTORY} DEFINITION SKIPPED_MODULES )
|
|
||||||
if ( _skip )
|
|
||||||
set( SKIPPED_MODULES ${_skip} PARENT_SCOPE )
|
|
||||||
set( MODULE_CONFIG_FILES "" )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if ( SKIPPED_MODULES )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
# ...otherwise, we look for a module.desc.
|
|
||||||
elseif( EXISTS "${_mod_dir}/module.desc" )
|
|
||||||
set( MODULES_DIR ${CMAKE_INSTALL_LIBDIR}/calamares/modules )
|
|
||||||
set( MODULE_DESTINATION ${MODULES_DIR}/${_modulename} )
|
|
||||||
|
|
||||||
# Read module.desc, check that the interface type is supported.
|
|
||||||
#
|
|
||||||
# _mod_enabled boolean if the module should be built (only if the interface is supported)
|
|
||||||
# _mod_reason is a human-readable explanation why it isn't built
|
|
||||||
# _mod_testing boolean if the module should be added to the loadmodule tests
|
|
||||||
file(STRINGS "${_mod_dir}/module.desc" MODULE_INTERFACE REGEX "^interface")
|
|
||||||
if ( MODULE_INTERFACE MATCHES "pythonqt" )
|
|
||||||
message( FATAL_ERROR "PythonQt is no longer supported" )
|
|
||||||
set( _mod_enabled OFF )
|
|
||||||
set( _mod_reason "No PythonQt support" )
|
|
||||||
set( _mod_testing OFF )
|
|
||||||
elseif ( MODULE_INTERFACE MATCHES "python" )
|
|
||||||
set( _mod_enabled ${Calamares_WITH_PYTHON} )
|
|
||||||
set( _mod_reason "No Python support" )
|
|
||||||
set( _mod_testing ON ) # Will check syntax and imports, at least
|
|
||||||
elseif ( MODULE_INTERFACE MATCHES "qtplugin" )
|
|
||||||
set( _mod_enabled OFF )
|
|
||||||
set( _mod_reason "C++ modules must have a CMakeLists.txt instead" )
|
|
||||||
set( _mod_testing OFF )
|
|
||||||
elseif ( MODULE_INTERFACE MATCHES "process" )
|
|
||||||
set( _mod_enabled ON )
|
|
||||||
set( _mod_reason "" )
|
|
||||||
set( _mod_testing OFF )
|
|
||||||
else()
|
|
||||||
set( _mod_enabled OFF )
|
|
||||||
set( _mod_reason "Unknown module interface '${MODULE_INTERFACE}'" )
|
|
||||||
set( _mod_testing OFF )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ( _mod_enabled )
|
|
||||||
# We glob all the files inside the subdirectory, and we make sure they are
|
|
||||||
# synced with the bindir structure and installed.
|
|
||||||
file( GLOB MODULE_FILES RELATIVE ${_mod_dir} "${SUBDIRECTORY}/*" )
|
|
||||||
foreach( MODULE_FILE ${MODULE_FILES} )
|
|
||||||
if( NOT IS_DIRECTORY ${_mod_dir}/${MODULE_FILE} )
|
|
||||||
configure_file( ${SUBDIRECTORY}/${MODULE_FILE} ${SUBDIRECTORY}/${MODULE_FILE} COPYONLY )
|
|
||||||
|
|
||||||
get_filename_component( FLEXT ${MODULE_FILE} EXT )
|
|
||||||
if( "${FLEXT}" STREQUAL ".conf" )
|
|
||||||
message(STATUS "Config ${MODULE_FILE}")
|
|
||||||
list( APPEND MODULE_CONFIG_FILES ${MODULE_FILE} )
|
|
||||||
else()
|
|
||||||
message(STATUS "Non-Config ${MODULE_FILE}")
|
|
||||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
|
|
||||||
DESTINATION ${MODULE_DESTINATION} )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${_modulename}${ColorReset}" )
|
|
||||||
message( " ${Green}TYPE:${ColorReset} jobmodule" )
|
|
||||||
message( " ${Green}MODULE_DESTINATION:${ColorReset} ${MODULE_DESTINATION}" )
|
|
||||||
if( MODULE_CONFIG_FILES )
|
|
||||||
if (INSTALL_CONFIG)
|
|
||||||
message(" ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => [Build directory and ${MODULE_DATA_DESTINATION}]")
|
|
||||||
foreach(_cf ${MODULE_CONFIG_FILES})
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${_cf} DESTINATION ${MODULE_DATA_DESTINATION})
|
|
||||||
endforeach()
|
|
||||||
else()
|
|
||||||
message(" ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => [Build directory only]")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
message( "" )
|
|
||||||
# We copy over the lang directory, if any
|
|
||||||
if( IS_DIRECTORY "${_mod_dir}/lang" )
|
|
||||||
install_calamares_gettext_translations(
|
|
||||||
${SUBDIRECTORY}
|
|
||||||
SOURCE_DIR "${_mod_dir}/lang"
|
|
||||||
FILENAME ${SUBDIRECTORY}.mo
|
|
||||||
RENAME calamares-${SUBDIRECTORY}.mo
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
# Module disabled due to missing dependencies / unsupported interface
|
|
||||||
set( SKIPPED_MODULES "${SUBDIRECTORY} (${_mod_reason})" PARENT_SCOPE )
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message( "-- ${BoldYellow}Warning:${ColorReset} tried to add module subdirectory ${BoldRed}${SUBDIRECTORY}${ColorReset} which has no CMakeLists.txt or module.desc." )
|
|
||||||
message( "" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Check any config files for basic correctness
|
|
||||||
if ( BUILD_TESTING AND MODULE_CONFIG_FILES )
|
|
||||||
set( _count 0 )
|
|
||||||
foreach( _config_file ${MODULE_CONFIG_FILES} )
|
|
||||||
set( _count_str "-${_count}" )
|
|
||||||
if ( _count EQUAL 0 )
|
|
||||||
set( _count_str "" )
|
|
||||||
endif()
|
|
||||||
add_test(
|
|
||||||
NAME config-${SUBDIRECTORY}${_count_str}
|
|
||||||
COMMAND test_conf ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${_config_file} )
|
|
||||||
math( EXPR _count "${_count} + 1" )
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Adding general tests
|
|
||||||
#
|
|
||||||
# Add a check that the module can be loaded. Since this calls exec(), the module
|
|
||||||
# may try to do things to the running system. Needs work to make that a
|
|
||||||
# safe thing to do.
|
|
||||||
#
|
|
||||||
# If the module has a tests/ subdirectory with *.global and *.job
|
|
||||||
# files (YAML files holding global and job-configurations for
|
|
||||||
# testing purposes) then those files are used to drive additional
|
|
||||||
# tests. The files must be numbered (starting from 1) for this to work;
|
|
||||||
# 1.global and 1.job together make the configuration for test 1.
|
|
||||||
#
|
|
||||||
# If the module has a tests/CMakeLists.txt while it doesn't have its
|
|
||||||
# own CMakeLists.txt (e.g. a Python module), then the subdirectory
|
|
||||||
# for tests/ is added on its own.
|
|
||||||
#
|
|
||||||
if ( BUILD_TESTING AND _mod_enabled AND _mod_testing )
|
|
||||||
add_test(
|
|
||||||
NAME load-${SUBDIRECTORY}
|
|
||||||
COMMAND loadmodule ${SUBDIRECTORY}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
||||||
)
|
|
||||||
# Try it with the tests/ configurations shipped with the module
|
|
||||||
set( _count 1 )
|
|
||||||
set( _testdir ${_mod_dir}/tests )
|
|
||||||
while ( EXISTS "${_testdir}/${_count}.global" OR EXISTS "${_testdir}/${_count}.job" )
|
|
||||||
set( _dash_g "" )
|
|
||||||
set( _dash_j "" )
|
|
||||||
if ( EXISTS "${_testdir}/${_count}.global" )
|
|
||||||
set( _dash_g -g ${_testdir}/${_count}.global )
|
|
||||||
endif()
|
|
||||||
if ( EXISTS "${_testdir}/${_count}.job" )
|
|
||||||
set( _dash_j -j ${_testdir}/${_count}.job )
|
|
||||||
endif()
|
|
||||||
add_test(
|
|
||||||
NAME load-${SUBDIRECTORY}-${_count}
|
|
||||||
COMMAND loadmodule ${_dash_g} ${_dash_j} ${SUBDIRECTORY}
|
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
|
||||||
)
|
|
||||||
math( EXPR _count "${_count} + 1" )
|
|
||||||
endwhile()
|
|
||||||
if ( EXISTS ${_testdir}/CMakeTests.txt AND NOT EXISTS ${_mod_dir}/CMakeLists.txt )
|
|
||||||
include( ${_testdir}/CMakeTests.txt )
|
|
||||||
endif()
|
|
||||||
if ( PYLINT_COMMAND AND MODULE_INTERFACE MATCHES "python" )
|
|
||||||
# Python modules get an additional test via pylint; this
|
|
||||||
# needs to run at top-level because the ci/libcalamares directory
|
|
||||||
# contains API stubs.
|
|
||||||
#
|
|
||||||
# TODO: the entry point is assumed to be `main.py`, but that is
|
|
||||||
# configurable through module.desc
|
|
||||||
add_test(
|
|
||||||
NAME lint-${SUBDIRECTORY}
|
|
||||||
COMMAND env PYTHONPATH=ci: ${PYLINT_COMMAND} -E ${_mod_dir}/main.py
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function( calamares_add_module_subdirectory )
|
|
||||||
set( SUBDIRECTORY ${ARGV0} )
|
|
||||||
set( _ams_SKIP_LIST ${ARGV1} )
|
|
||||||
|
|
||||||
set( SKIPPED_MODULES "" )
|
|
||||||
_calamares_add_module_subdirectory_impl( ${SUBDIRECTORY} )
|
|
||||||
if ( SKIPPED_MODULES )
|
|
||||||
if ( _ams_SKIP_LIST )
|
|
||||||
list( APPEND ${_ams_SKIP_LIST} "${SKIPPED_MODULES}" )
|
|
||||||
set( ${_ams_SKIP_LIST} "${${_ams_SKIP_LIST}}" PARENT_SCOPE )
|
|
||||||
else()
|
|
||||||
set( SKIPPED_MODULES "${SKIPPED_MODULES}" PARENT_SCOPE )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
@ -1,233 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Convenience function for creating a C++ (qtplugin) module for Calamares.
|
|
||||||
# This function provides cmake-time feedback about the plugin, adds
|
|
||||||
# targets for compilation and boilerplate information, and creates
|
|
||||||
# a module.desc with standard values (if the module.desc file exists,
|
|
||||||
# that one is used instead, which happens only for unusual plugins).
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# calamares_add_plugin(
|
|
||||||
# module-name
|
|
||||||
# TYPE <viewmodule|job>
|
|
||||||
# EXPORT_MACRO macro-name
|
|
||||||
# SOURCES source-file...
|
|
||||||
# UI ui-file...
|
|
||||||
# LINK_LIBRARIES lib...
|
|
||||||
# LINK_PRIVATE_LIBRARIES lib...
|
|
||||||
# [COMPILE_DEFINITIONS def...]
|
|
||||||
# [RESOURCES resource-file]
|
|
||||||
# [REQUIRES module-name...]
|
|
||||||
# [NO_INSTALL]
|
|
||||||
# [NO_CONFIG]
|
|
||||||
# [SHARED_LIB]
|
|
||||||
# [EMERGENCY]
|
|
||||||
# [WEIGHT w]
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# Function optional parameters:
|
|
||||||
# - COMPILE_DEFINITIONS
|
|
||||||
# Definitions are set on the resulting module with a suitable
|
|
||||||
# flag (i.e. `-D`) so only state the name (optionally, also the value)
|
|
||||||
# without a `-D` prefixed to it.
|
|
||||||
# - RESOURCES
|
|
||||||
# One (single!) filename for the RCC file for the plugin.
|
|
||||||
# - REQUIRES
|
|
||||||
# One or more names of modules which are added to the *requiredModules*
|
|
||||||
# key in the descriptor. See *Module Requirements* in the module
|
|
||||||
# documentation.
|
|
||||||
# - NO_INSTALL
|
|
||||||
# If this is set, the module is not installed by default; use this to
|
|
||||||
# build testing modules or unit-testing modules.
|
|
||||||
# - SHARED_LIB
|
|
||||||
# In unusual circumstances, this function is used to add a library
|
|
||||||
# rather than a normal Calamares module / plugin.
|
|
||||||
# - EMERGENCY
|
|
||||||
# If this is set, the module is marked as an *emergency* module in the
|
|
||||||
# descriptor. See *Emergency Modules* in the module documentation.
|
|
||||||
# - WEIGHT
|
|
||||||
# If this is set, writes an explicit weight into the module.desc;
|
|
||||||
# module weights are used in progress reporting.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# This function follows the global SKIP_MODULES and USE_* settings, so
|
|
||||||
# a plugin may be skipped -- then nothing will be built. In that case,
|
|
||||||
# SKIPPED_MODULES is set in the parent (i.e. caller's) scope with the
|
|
||||||
# reason why. This should rarely be a concern as AddModuleSubdirectory
|
|
||||||
# already handles skip-reasons and collects them for reporting.
|
|
||||||
#
|
|
||||||
# The target defined this way is called "calamares_<TYPE>_<module-name>",
|
|
||||||
# e.g. "calamares_viewmodule_packagechooserq". The function sets a variable
|
|
||||||
# in its **calling** scope, `<module-name>_TARGET` with the full name
|
|
||||||
# of the target.
|
|
||||||
|
|
||||||
include( CMakeParseArguments )
|
|
||||||
|
|
||||||
include( CalamaresAddLibrary )
|
|
||||||
include( CalamaresCheckModuleSelection )
|
|
||||||
include( CMakeColors )
|
|
||||||
|
|
||||||
function( calamares_add_plugin )
|
|
||||||
# parse arguments ( name needs to be saved before passing ARGN into the macro )
|
|
||||||
set( NAME ${ARGV0} )
|
|
||||||
set( options NO_CONFIG NO_INSTALL SHARED_LIB EMERGENCY )
|
|
||||||
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES WEIGHT )
|
|
||||||
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS REQUIRES )
|
|
||||||
cmake_parse_arguments( PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
|
||||||
set( PLUGIN_NAME ${NAME} )
|
|
||||||
set( PLUGIN_DESTINATION ${CMAKE_INSTALL_LIBDIR}/calamares/modules/${PLUGIN_NAME} )
|
|
||||||
set( PLUGIN_DESC_FILE module.desc )
|
|
||||||
file( GLOB PLUGIN_CONFIG_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.conf" )
|
|
||||||
set( PLUGIN_DATA_DESTINATION share/calamares/modules )
|
|
||||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
|
||||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
|
||||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
|
||||||
|
|
||||||
calamares_check_skip( ${NAME} _skip)
|
|
||||||
if ( _skip )
|
|
||||||
set( SKIPPED_MODULES "${_skip}" PARENT_SCOPE )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${PLUGIN_NAME}${ColorReset}" )
|
|
||||||
message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" )
|
|
||||||
message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" )
|
|
||||||
message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
|
|
||||||
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
|
|
||||||
if( PLUGIN_CONFIG_FILES )
|
|
||||||
if( PLUGIN_NO_CONFIG )
|
|
||||||
message( FATAL_ERROR "${Red}NO_CONFIG${ColorReset} is set, with configuration ${Red}${PLUGIN_CONFIG_FILES}${ColorReset}" )
|
|
||||||
endif()
|
|
||||||
set( _destination "(unknown)" )
|
|
||||||
if(INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL)
|
|
||||||
set(_destination "${PLUGIN_DATA_DESTINATION}")
|
|
||||||
elseif( NOT PLUGIN_NO_INSTALL )
|
|
||||||
set( _destination "[Build directory only]" )
|
|
||||||
else()
|
|
||||||
set( _destination "[Skipping installation]" )
|
|
||||||
endif()
|
|
||||||
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${_destination}" )
|
|
||||||
else()
|
|
||||||
if( NOT PLUGIN_NO_CONFIG )
|
|
||||||
message( " ${Red}NO_CONFIG${ColorReset} should be set." )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if( PLUGIN_RESOURCES )
|
|
||||||
message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" )
|
|
||||||
endif()
|
|
||||||
message( "" )
|
|
||||||
|
|
||||||
# create target name once for convenience
|
|
||||||
set( target "calamares_${PLUGIN_TYPE}_${PLUGIN_NAME}" )
|
|
||||||
|
|
||||||
# automatic library linkage
|
|
||||||
if(PLUGIN_TYPE STREQUAL "viewmodule")
|
|
||||||
list(APPEND PLUGIN_LINK_PRIVATE_LIBRARIES Calamares::calamaresui)
|
|
||||||
elseif(PLUGIN_TYPE STREQUAL "job")
|
|
||||||
list(APPEND PLUGIN_LINK_PRIVATE_LIBRARIES Calamares::calamares)
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Unknown plugin type ${PLUGIN_TYPE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# determine target type
|
|
||||||
if( NOT ${PLUGIN_SHARED_LIB} )
|
|
||||||
set( target_type "MODULE" )
|
|
||||||
else()
|
|
||||||
set( target_type "SHARED" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( calamares_add_library_args
|
|
||||||
"${target}"
|
|
||||||
"EXPORT_MACRO" "${PLUGIN_EXPORT_MACRO}"
|
|
||||||
"TARGET_TYPE" "${target_type}"
|
|
||||||
"SOURCES" "${PLUGIN_SOURCES}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if( PLUGIN_UI )
|
|
||||||
list( APPEND calamares_add_library_args "UI" "${PLUGIN_UI}" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( PLUGIN_LINK_LIBRARIES )
|
|
||||||
list( APPEND calamares_add_library_args "LINK_LIBRARIES" "${PLUGIN_LINK_LIBRARIES}" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( PLUGIN_LINK_PRIVATE_LIBRARIES )
|
|
||||||
list( APPEND calamares_add_library_args "LINK_PRIVATE_LIBRARIES" "${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( PLUGIN_COMPILE_DEFINITIONS )
|
|
||||||
list( APPEND calamares_add_library_args "COMPILE_DEFINITIONS" ${PLUGIN_COMPILE_DEFINITIONS} )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ( PLUGIN_NO_INSTALL )
|
|
||||||
list( APPEND calamares_add_library_args "NO_INSTALL" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list( APPEND calamares_add_library_args
|
|
||||||
"NO_VERSION"
|
|
||||||
"INSTALL_BINDIR" "${PLUGIN_DESTINATION}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if( PLUGIN_RESOURCES )
|
|
||||||
list( APPEND calamares_add_library_args "RESOURCES" "${PLUGIN_RESOURCES}" )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
calamares_add_library( ${calamares_add_library_args} )
|
|
||||||
|
|
||||||
if ( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PLUGIN_DESC_FILE} )
|
|
||||||
configure_file( ${PLUGIN_DESC_FILE} ${PLUGIN_DESC_FILE} COPYONLY )
|
|
||||||
else()
|
|
||||||
set( _file ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE} )
|
|
||||||
set( _type ${PLUGIN_TYPE} )
|
|
||||||
file( WRITE ${_file} "# AUTO-GENERATED metadata file\n# Syntax is YAML 1.2\n---\n" )
|
|
||||||
file( APPEND ${_file} "type: \"${_type}\"\nname: \"${PLUGIN_NAME}\"\ninterface: \"qtplugin\"\nload: \"lib${target}.so\"\n" )
|
|
||||||
if ( PLUGIN_REQUIRES )
|
|
||||||
file( APPEND ${_file} "requiredModules:\n" )
|
|
||||||
foreach( _r ${PLUGIN_REQUIRES} )
|
|
||||||
file( APPEND ${_file} " - ${_r}\n" )
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
if ( PLUGIN_EMERGENCY )
|
|
||||||
file( APPEND ${_file} "emergency: true\n" )
|
|
||||||
endif()
|
|
||||||
if ( PLUGIN_NO_CONFIG )
|
|
||||||
file( APPEND ${_file} "noconfig: true\n" )
|
|
||||||
endif()
|
|
||||||
if ( PLUGIN_WEIGHT )
|
|
||||||
file( APPEND ${_file} "weight: ${PLUGIN_WEIGHT}\n" )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ( NOT PLUGIN_NO_INSTALL )
|
|
||||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
|
||||||
DESTINATION ${PLUGIN_DESTINATION} )
|
|
||||||
|
|
||||||
set( _warned_config OFF )
|
|
||||||
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
|
|
||||||
if( ${CMAKE_CURRENT_SOURCE_DIR}/${PLUGIN_CONFIG_FILE} IS_NEWER_THAN ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE} )
|
|
||||||
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
|
|
||||||
else()
|
|
||||||
message( " ${BoldYellow}Not updating${ColorReset} ${PLUGIN_CONFIG_FILE}" )
|
|
||||||
set( _warned_config ON )
|
|
||||||
endif()
|
|
||||||
if(INSTALL_CONFIG)
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE} DESTINATION ${PLUGIN_DATA_DESTINATION})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
if ( _warned_config )
|
|
||||||
message( "" )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${NAME}_TARGET ${target} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
@ -1,56 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Support functions for building Calamares tests.
|
|
||||||
# This extends KDE's ECM tests with some custom patterns.
|
|
||||||
#
|
|
||||||
# calamares_add_test(
|
|
||||||
# <NAME>
|
|
||||||
# [GUI]
|
|
||||||
# [RESOURCES FILE]
|
|
||||||
# SOURCES <FILE..>
|
|
||||||
# )
|
|
||||||
|
|
||||||
include(CMakeParseArguments)
|
|
||||||
include(CalamaresAutomoc)
|
|
||||||
|
|
||||||
function(calamares_add_test name)
|
|
||||||
set(options GUI)
|
|
||||||
set(oneValueArgs RESOURCES)
|
|
||||||
set(multiValueArgs SOURCES LIBRARIES DEFINITIONS)
|
|
||||||
cmake_parse_arguments(TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
set(TEST_NAME ${name})
|
|
||||||
|
|
||||||
if(ECM_FOUND AND BUILD_TESTING)
|
|
||||||
ecm_add_test(
|
|
||||||
${TEST_SOURCES} ${TEST_RESOURCES}
|
|
||||||
TEST_NAME
|
|
||||||
${TEST_NAME}
|
|
||||||
LINK_LIBRARIES
|
|
||||||
Calamares::calamares
|
|
||||||
${TEST_LIBRARIES}
|
|
||||||
${qtname}::Core
|
|
||||||
${qtname}::Test
|
|
||||||
)
|
|
||||||
calamares_automoc( ${TEST_NAME} )
|
|
||||||
# We specifically pass in the source directory of the test-being-
|
|
||||||
# compiled, so that it can find test-files in that source dir.
|
|
||||||
target_compile_definitions(
|
|
||||||
${TEST_NAME}
|
|
||||||
PRIVATE -DBUILD_AS_TEST="${CMAKE_CURRENT_SOURCE_DIR}" ${TEST_DEFINITIONS}
|
|
||||||
)
|
|
||||||
if(TEST_GUI)
|
|
||||||
target_link_libraries(${TEST_NAME} Calamares::calamaresui ${qtname}::Gui)
|
|
||||||
endif()
|
|
||||||
if(TEST_RESOURCES)
|
|
||||||
calamares_autorcc( ${TEST_NAME} ${TEST_RESOURCES} )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
@ -1,158 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This file has not yet been documented for use outside of Calamares itself.
|
|
||||||
|
|
||||||
include(CMakeParseArguments)
|
|
||||||
include(FeatureSummary)
|
|
||||||
|
|
||||||
# The Gettext module is still old-fashioned, ALLCAPS variables
|
|
||||||
find_package( Gettext )
|
|
||||||
set_package_properties( GETTEXT PROPERTIES
|
|
||||||
DESCRIPTION "GNU gettext (translation) tools."
|
|
||||||
URL "https://www.gnu.org/software/gettext/"
|
|
||||||
PURPOSE "Gettext is used in the translation of Python modules."
|
|
||||||
TYPE REQUIRED
|
|
||||||
)
|
|
||||||
|
|
||||||
# Installs a directory containing language-code-labeled subdirectories with
|
|
||||||
# gettext data into the appropriate system directory. Allows renaming the
|
|
||||||
# .mo files during install to avoid namespace clashes.
|
|
||||||
#
|
|
||||||
# install_calamares_gettext_translations(
|
|
||||||
# NAME <name of module, for human use>
|
|
||||||
# SOURCE_DIR path/to/lang
|
|
||||||
# FILENAME <name of file.mo>
|
|
||||||
# [RENAME <new-name of.mo>]
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# For all of the (global) translation languages enabled for Calamares,
|
|
||||||
# try installing $SOURCE_DIR/$lang/LC_MESSAGES/<filename>.mo into the
|
|
||||||
# system gettext data directory (e.g. share/locale/), possibly renaming
|
|
||||||
# filename.mo to renamed.mo in the process.
|
|
||||||
function( install_calamares_gettext_translations )
|
|
||||||
# parse arguments ( name needs to be saved before passing ARGN into the macro )
|
|
||||||
set( NAME ${ARGV0} )
|
|
||||||
set( oneValueArgs NAME SOURCE_DIR FILENAME RENAME )
|
|
||||||
cmake_parse_arguments( TRANSLATION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
|
||||||
|
|
||||||
if( NOT TRANSLATION_NAME )
|
|
||||||
set( TRANSLATION_NAME ${NAME} )
|
|
||||||
endif()
|
|
||||||
if( NOT TRANSLATION_FILENAME )
|
|
||||||
set( TRANSLATION_FILENAME "${TRANSLATION_NAME}.mo" )
|
|
||||||
endif()
|
|
||||||
if( NOT TRANSLATION_RENAME )
|
|
||||||
set( TRANSLATION_RENAME "${TRANSLATION_FILENAME}" )
|
|
||||||
endif()
|
|
||||||
string( REGEX REPLACE ".mo$" ".po" TRANSLATION_SOURCE_FILENAME "${TRANSLATION_FILENAME}" )
|
|
||||||
|
|
||||||
if ( GETTEXT_FOUND AND GETTEXT_MSGFMT_EXECUTABLE )
|
|
||||||
message( STATUS "Installing gettext translations for ${TRANSLATION_NAME}")
|
|
||||||
message( STATUS " Installing ${TRANSLATION_FILENAME} from ${TRANSLATION_SOURCE_DIR}")
|
|
||||||
else()
|
|
||||||
message( WARNING "Gettext translations requested for ${TRANSLATION_NAME}, but gettext was not found." )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( TARGET_NAME calamares-gettext-translations-${NAME} )
|
|
||||||
if( NOT TARGET "${TARGET_NAME}" )
|
|
||||||
add_custom_target( "${TARGET_NAME}" ALL )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set( TRANSLATION_NAME "${NAME}" )
|
|
||||||
foreach( lang ${CALAMARES_TRANSLATION_LANGUAGES} ) # Global
|
|
||||||
string( MAKE_C_IDENTIFIER "${TARGET_NAME}-${lang}" TARGET_SUBNAME )
|
|
||||||
|
|
||||||
set( lang_po "${TRANSLATION_SOURCE_DIR}/${lang}/LC_MESSAGES/${TRANSLATION_SOURCE_FILENAME}" )
|
|
||||||
set( lang_mo_dir "${CMAKE_BINARY_DIR}/lang/${lang}/LC_MESSAGES" )
|
|
||||||
set( lang_mo "${lang_mo_dir}/${TRANSLATION_RENAME}" )
|
|
||||||
if( lang STREQUAL "en" )
|
|
||||||
message( STATUS " Skipping ${TRANSLATION_NAME} translations for en_US" )
|
|
||||||
else()
|
|
||||||
# We **don't** use the gettext macro's here because the source
|
|
||||||
# structure doesn't match: we are calling this once per language
|
|
||||||
# for all of Calamares's languages, while the gettext module
|
|
||||||
# expects it to be called once, for a given language source-dir.
|
|
||||||
#
|
|
||||||
# Using any of the gettext macros just gets us multiple rules
|
|
||||||
# for python.gmo, and it wants to use msgmerge, besides, which
|
|
||||||
# doesn't fit our Transifex workflow.
|
|
||||||
make_directory( ${lang_mo_dir} )
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${lang_mo}
|
|
||||||
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE}
|
|
||||||
ARGS -o ${lang_mo} ${lang_po}
|
|
||||||
MAIN_DEPENDENCY ${lang_po}
|
|
||||||
)
|
|
||||||
add_custom_target( "${TARGET_SUBNAME}" DEPENDS ${lang_mo} )
|
|
||||||
add_dependencies( "${TARGET_NAME}" "${TARGET_SUBNAME}" )
|
|
||||||
install(
|
|
||||||
FILES ${lang_mo}
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${lang}/LC_MESSAGES/
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
set(_calamares_qrc_translations_qrc_source ${CMAKE_CURRENT_LIST_DIR}/i18n.qrc.in) # Needs to be set outside of function
|
|
||||||
function(calamares_qrc_translations basename)
|
|
||||||
set(options "")
|
|
||||||
set(oneValueArgs SUBDIRECTORY OUTPUT_VARIABLE)
|
|
||||||
set(multiValueArgs PREFIXES LANGUAGES)
|
|
||||||
cmake_parse_arguments(_qrt "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT _qrt_OUTPUT_VARIABLE)
|
|
||||||
message(FATAL_ERROR "No output variable")
|
|
||||||
endif()
|
|
||||||
if(NOT _qrt_PREFIXES)
|
|
||||||
set(_qrt_PREFIXES "${basename}")
|
|
||||||
endif()
|
|
||||||
if(NOT _qrt_LANGUAGES)
|
|
||||||
set(_qrt_LANGUAGES ${CALAMARES_TRANSLATION_LANGUAGES})
|
|
||||||
endif()
|
|
||||||
if(NOT _qrt_SUBDIRECTORY)
|
|
||||||
set(_qrt_SUBDIRECTORY "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(translations_qrc_infile ${CMAKE_CURRENT_BINARY_DIR}/${basename}.qrc)
|
|
||||||
set(translations_qrc_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${basename}.cxx)
|
|
||||||
|
|
||||||
# Must use this variable name because of the @ substitution
|
|
||||||
set(calamares_i18n_qrc_content "")
|
|
||||||
set(calamares_i18n_ts_filelist "")
|
|
||||||
foreach(lang ${_qrt_LANGUAGES})
|
|
||||||
foreach(tlsource ${_qrt_PREFIXES})
|
|
||||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_qrt_SUBDIRECTORY}/${tlsource}_${lang}.ts")
|
|
||||||
string(APPEND calamares_i18n_qrc_content "<file>${tlsource}_${lang}.qm</file>\n")
|
|
||||||
list(APPEND calamares_i18n_ts_filelist "${CMAKE_CURRENT_SOURCE_DIR}/${_qrt_SUBDIRECTORY}/${tlsource}_${lang}.ts")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
configure_file(${_calamares_qrc_translations_qrc_source} ${translations_qrc_infile} @ONLY)
|
|
||||||
qt_add_translation(QM_FILES ${calamares_i18n_ts_filelist})
|
|
||||||
|
|
||||||
# Run the resource compiler (rcc_options should already be set)
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${translations_qrc_outfile}
|
|
||||||
COMMAND ${qtname}::rcc
|
|
||||||
ARGS
|
|
||||||
${rcc_options}
|
|
||||||
--format-version 1
|
|
||||||
-name ${basename}
|
|
||||||
-o ${translations_qrc_outfile}
|
|
||||||
${translations_qrc_infile}
|
|
||||||
MAIN_DEPENDENCY ${translations_qrc_infile}
|
|
||||||
DEPENDS ${QM_FILES}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(${_qrt_OUTPUT_VARIABLE} ${translations_qrc_outfile} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
@ -1,57 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Helper function for doing automoc, autouic, autorcc on targets,
|
|
||||||
# and on the corresponding .ui or .rcc files.
|
|
||||||
#
|
|
||||||
# calamares_automoc(target)
|
|
||||||
# Sets AUTOMOC TRUE for a target.
|
|
||||||
#
|
|
||||||
# If the global variable CALAMARES_AUTOMOC_OPTIONS is set, uses that
|
|
||||||
# as well to set options passed to MOC. This can be used to add
|
|
||||||
# libcalamares/utils/moc-warnings.h file to the moc, which in turn
|
|
||||||
# reduces compiler warnings in generated MOC code.
|
|
||||||
#
|
|
||||||
# calamares_autouic(target [uifile ..])
|
|
||||||
# Sets AUTOUIC TRUE for a target.
|
|
||||||
#
|
|
||||||
# If the global variable CALAMARES_AUTOUIC_OPTIONS is set, adds that
|
|
||||||
# to the options passed to uic for each of the named uifiles.
|
|
||||||
#
|
|
||||||
# calamares_autorcc(target [rcfile ..])
|
|
||||||
# Sets AUTOUIC TRUE for a target.
|
|
||||||
#
|
|
||||||
# If the global variable CALAMARES_AUTORCC_OPTIONS is set, adds that
|
|
||||||
# to the options passed to rcc for each of the named rcfiles.
|
|
||||||
|
|
||||||
function(calamares_automoc TARGET)
|
|
||||||
set_target_properties( ${TARGET} PROPERTIES AUTOMOC TRUE )
|
|
||||||
if ( CALAMARES_AUTOMOC_OPTIONS )
|
|
||||||
set_target_properties( ${TARGET} PROPERTIES AUTOMOC_MOC_OPTIONS "${CALAMARES_AUTOMOC_OPTIONS}" )
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(calamares_autouic TARGET)
|
|
||||||
set_target_properties( ${TARGET} PROPERTIES AUTOUIC TRUE )
|
|
||||||
if ( CALAMARES_AUTOUIC_OPTIONS )
|
|
||||||
foreach(S ${ARGN})
|
|
||||||
set_property(SOURCE ${S} PROPERTY AUTOUIC_OPTIONS "${CALAMARES_AUTOUIC_OPTIONS}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(calamares_autorcc TARGET)
|
|
||||||
set_target_properties( ${TARGET} PROPERTIES AUTORCC TRUE )
|
|
||||||
if ( CALAMARES_AUTORCC_OPTIONS )
|
|
||||||
foreach(S ${ARGN})
|
|
||||||
set_property(SOURCE ${S} PROPERTY AUTORCC_OPTIONS "${CALAMARES_AUTORCC_OPTIONS}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
@ -1,116 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This module implements the "skip modules" part of configuring
|
|
||||||
# the Calamares repository or an external-modules repository.
|
|
||||||
#
|
|
||||||
# It should not be necessary to include() this module explicitly,
|
|
||||||
# since both AddPlugin and AddModuleSubdirectory do so implicitly.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # Usage
|
|
||||||
#
|
|
||||||
# The public API is two functions:
|
|
||||||
#
|
|
||||||
# - calamares_skip_module(reason)
|
|
||||||
# A C++ module (or any that uses CMake) can call this macro to
|
|
||||||
# add *reason* to the list of skipped modules. Typically a module
|
|
||||||
# will pass in "modulename (why)" so that it is clear **which**
|
|
||||||
# module is skipped. This macro should be called at the top-level
|
|
||||||
# of a module's CMakeLists.txt and the module should then **not**
|
|
||||||
# call calamares_add_plugin().
|
|
||||||
# - calamares_explain_skipped_modules(list...)
|
|
||||||
# This will print out all the module reasons (see above) that have
|
|
||||||
# been added to the given *listvar*. When AddModuleSubdirectory is
|
|
||||||
# used as the mechanism to add all the subdirectories in the repository
|
|
||||||
# that contain modules, with a consistent *listvar* setting,
|
|
||||||
# this will show all the modules that have been skipped.
|
|
||||||
#
|
|
||||||
# The internal API is one function:
|
|
||||||
#
|
|
||||||
# - calamares_check_skip(modulename outvar)
|
|
||||||
# Checks if the *modulename* has been listed in the global SKIP_MODULES
|
|
||||||
# variable (to skip specifically-named modules) or if there is a USE_*
|
|
||||||
# setting applicable to the module. If the module is skipped for this
|
|
||||||
# reason, a suitable entry is added to *outvar* as if
|
|
||||||
# calamares_skip_module() had been called.
|
|
||||||
#
|
|
||||||
# Best practice is to pick a variable to collect all of the skipped
|
|
||||||
# modules, and to pass the name of that variable to AddModuleSubdirectory
|
|
||||||
# in each call. After all subdirectories have been added, call
|
|
||||||
# calamares_explain_skipped_modules() with the value of that variable.
|
|
||||||
|
|
||||||
|
|
||||||
# Convenience function to indicate that a module has been skipped
|
|
||||||
# (optionally also why). Call this in the module's CMakeLists.txt
|
|
||||||
macro( calamares_skip_module )
|
|
||||||
set( SKIPPED_MODULES ${SKIPPED_MODULES} ${ARGV} PARENT_SCOPE )
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
function( calamares_explain_skipped_modules )
|
|
||||||
if ( ARGN )
|
|
||||||
message( "${ColorReset}-- Skipped modules:" )
|
|
||||||
foreach( SUBDIRECTORY ${ARGN} )
|
|
||||||
message( "${ColorReset}-- Skipped ${BoldRed}${SUBDIRECTORY}${ColorReset}." )
|
|
||||||
endforeach()
|
|
||||||
message( "" )
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Globally, SKIP_MODULES and USE_* affect what modules are built.
|
|
||||||
# Check if *modulename* should be skipped, and if so, set *outvar* to
|
|
||||||
# a human-readable reason for skipping it.
|
|
||||||
function( _calamares_check_skip_impl modulename outvar )
|
|
||||||
# Globally-defined SKIP_MODULES may be space- or semicolon- separated
|
|
||||||
# so convert it to a list-variable.
|
|
||||||
string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" )
|
|
||||||
|
|
||||||
list( FIND SKIP_LIST "${modulename}" DO_SKIP )
|
|
||||||
if( NOT DO_SKIP EQUAL -1 )
|
|
||||||
set( ${outvar} "user request" PARENT_SCOPE )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Not skipped by the global check, see if it has an applicable USE_*
|
|
||||||
if( "${modulename}" MATCHES "^[a-zA-Z0-9_]+-" )
|
|
||||||
# Split the name into <category>-<implementation>
|
|
||||||
string( REGEX REPLACE "-.*" "" _category "${modulename}" )
|
|
||||||
string( REGEX REPLACE "^[^-]+-" "" _implementation "${modulename}" )
|
|
||||||
else()
|
|
||||||
# Not a module to which USE_* applies
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( "${USE_${_category}}" STREQUAL "none" )
|
|
||||||
set( ${outvar} "category ${_category} disabled" PARENT_SCOPE )
|
|
||||||
return()
|
|
||||||
elseif( "${USE_${_category}}" STREQUAL "" )
|
|
||||||
# Category not set at all or nonexistent
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if ( "${USE_${_category}}" STREQUAL "${_implementation}" )
|
|
||||||
# Matches, so accept this module
|
|
||||||
else()
|
|
||||||
set( ${outvar} "category ${_category} selects ${USE_${_category}}" PARENT_SCOPE )
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# This is the public API;it calls the _impl version so that there
|
|
||||||
# is an extra intermediate scope for the subdirectory to write results into.
|
|
||||||
function( calamares_check_skip modulename outvar )
|
|
||||||
set( _skip "" )
|
|
||||||
_calamares_check_skip_impl( "${modulename}" _skip )
|
|
||||||
if ( _skip )
|
|
||||||
message( "${ColorReset}-- Skipping module ${BoldRed}${modulename} (${_skip})${ColorReset}." )
|
|
||||||
message( "" )
|
|
||||||
set( ${outvar} "${modulename} (${_skip})" PARENT_SCOPE )
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
@ -1,70 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# This file defines one function for extending a VERSION-like value
|
|
||||||
# with date and git information (if desired).
|
|
||||||
#
|
|
||||||
# - extend_version( version-string short_only short_var long_var )
|
|
||||||
# Calling this function will copy *version-string* (which would typically
|
|
||||||
# be a semver-style string, like "3.2.40") into the variable *short_var*.
|
|
||||||
# If *short_only* is true, then:
|
|
||||||
# - the short version is also copied into the variable *long_var*,
|
|
||||||
# If *short_only* is false, then:
|
|
||||||
# - the *version-string* plus date and git information, is copied
|
|
||||||
# into the varialbe *long_var*, in the format {version}-{date}-{hash}
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
function( get_git_version_info out_var )
|
|
||||||
set(CMAKE_VERSION_SOURCE "")
|
|
||||||
if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD)
|
|
||||||
find_program(GIT_EXECUTABLE NAMES git git.cmd)
|
|
||||||
mark_as_advanced(GIT_EXECUTABLE)
|
|
||||||
if(GIT_EXECUTABLE)
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=8 HEAD
|
|
||||||
OUTPUT_VARIABLE head
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
if(head)
|
|
||||||
set(CMAKE_VERSION_SOURCE "${head}")
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
|
|
||||||
OUTPUT_VARIABLE dirty
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
if(dirty)
|
|
||||||
set(CMAKE_VERSION_SOURCE "${CMAKE_VERSION_SOURCE}-dirty")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
set( ${out_var} "${CMAKE_VERSION_SOURCE}" PARENT_SCOPE )
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function( extend_version version short_only short_var long_var )
|
|
||||||
set( ${short_var} "${version}" PARENT_SCOPE )
|
|
||||||
set( _v "${version}" )
|
|
||||||
if ( NOT short_only )
|
|
||||||
string( TIMESTAMP CALAMARES_VERSION_DATE "%Y%m%d" )
|
|
||||||
if( CALAMARES_VERSION_DATE GREATER 0 )
|
|
||||||
set( _v ${_v}.${CALAMARES_VERSION_DATE} )
|
|
||||||
endif()
|
|
||||||
get_git_version_info( _gitv )
|
|
||||||
if( _gitv )
|
|
||||||
set( _v "${_v}-${_gitv}" )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
set( ${long_var} "${_v}" PARENT_SCOPE )
|
|
||||||
endfunction()
|
|
@ -1,42 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# - Find libcrypt
|
|
||||||
# Find the libcrypt includes and the libcrypt libraries
|
|
||||||
# This module defines
|
|
||||||
# LIBCRYPT_INCLUDE_DIR, root crypt include dir. Include crypt with crypt.h
|
|
||||||
# LIBCRYPT_LIBRARY, the path to libcrypt
|
|
||||||
# LIBCRYPT_FOUND, whether libcrypt was found
|
|
||||||
|
|
||||||
if( CMAKE_SYSTEM MATCHES "FreeBSD" )
|
|
||||||
# FreeBSD has crypt(3) declared in unistd.h, which lives in
|
|
||||||
# libc; the libcrypt found here is not used.
|
|
||||||
find_path( CRYPT_INCLUDE_DIR NAMES unistd.h )
|
|
||||||
add_definitions( -DNO_CRYPT_H )
|
|
||||||
else()
|
|
||||||
find_path( CRYPT_INCLUDE_DIR
|
|
||||||
NAMES crypt.h
|
|
||||||
HINTS
|
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}
|
|
||||||
NO_CACHE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_library( CRYPT_LIBRARIES
|
|
||||||
NAMES crypt
|
|
||||||
HINTS
|
|
||||||
${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
include( FindPackageHandleStandardArgs )
|
|
||||||
find_package_handle_standard_args(
|
|
||||||
Crypt
|
|
||||||
REQUIRED_VARS CRYPT_LIBRARIES CRYPT_INCLUDE_DIR
|
|
||||||
)
|
|
||||||
|
|
||||||
mark_as_advanced( CRYPT_INCLUDE_DIR CRYPT_LIBRARIES )
|
|
@ -1,50 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Locate libpwquality
|
|
||||||
# https://github.com/libpwquality/libpwquality
|
|
||||||
#
|
|
||||||
# This module defines
|
|
||||||
# LibPWQuality_FOUND
|
|
||||||
# LibPWQuality_LIBRARIES, where to find the library
|
|
||||||
# LibPWQuality_INCLUDE_DIRS, where to find pwquality.h
|
|
||||||
#
|
|
||||||
find_package(PkgConfig)
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
|
|
||||||
if(PkgConfig_FOUND)
|
|
||||||
pkg_search_module(pc_pwquality QUIET pwquality)
|
|
||||||
else()
|
|
||||||
# It's just possible that the find_path and find_library will
|
|
||||||
# find it **anyway**, so let's pretend it was there.
|
|
||||||
set(pc_pwquality_FOUND ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_path(LibPWQuality_INCLUDE_DIR
|
|
||||||
NAMES pwquality.h
|
|
||||||
PATHS ${pc_pwquality_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
find_library(LibPWQuality_LIBRARY
|
|
||||||
NAMES pwquality
|
|
||||||
PATHS ${pc_pwquality_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
if(pc_pwquality_FOUND)
|
|
||||||
set(LibPWQuality_LIBRARIES ${LibPWQuality_LIBRARY})
|
|
||||||
set(LibPWQuality_INCLUDE_DIRS ${LibPWQuality_INCLUDE_DIR} ${pc_pwquality_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package_handle_standard_args(LibPWQuality DEFAULT_MSG
|
|
||||||
LibPWQuality_INCLUDE_DIRS
|
|
||||||
LibPWQuality_LIBRARIES
|
|
||||||
)
|
|
||||||
mark_as_advanced(LibPWQuality_INCLUDE_DIRS LibPWQuality_LIBRARIES)
|
|
||||||
|
|
||||||
set_package_properties(
|
|
||||||
LibPWQuality PROPERTIES
|
|
||||||
DESCRIPTION "Password quality checking library"
|
|
||||||
URL "https://github.com/libpwquality/libpwquality"
|
|
||||||
)
|
|
69
CMakeModules/FindPythonQt.cmake
Normal file
69
CMakeModules/FindPythonQt.cmake
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# Find PythonQt
|
||||||
|
#
|
||||||
|
# Sets PYTHONQT_FOUND, PYTHONQT_INCLUDE_DIR, PYTHONQT_LIBRARY, PYTHONQT_LIBRARIES
|
||||||
|
#
|
||||||
|
|
||||||
|
# Python is required
|
||||||
|
find_package(PythonLibs)
|
||||||
|
if(NOT PYTHONLIBS_FOUND)
|
||||||
|
message(FATAL_ERROR "error: Python is required to build PythonQt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${PYTHONQT_INSTALL_DIR}")
|
||||||
|
find_path(PYTHONQT_INSTALL_DIR include/PythonQt/PythonQt.h DOC "Directory where PythonQt was installed.")
|
||||||
|
endif()
|
||||||
|
# XXX Since PythonQt 3.0 is not yet cmakeified, depending
|
||||||
|
# on how PythonQt is built, headers will not always be
|
||||||
|
# installed in "include/PythonQt". That is why "src"
|
||||||
|
# is added as an option. See [1] for more details.
|
||||||
|
# [1] https://github.com/commontk/CTK/pull/538#issuecomment-86106367
|
||||||
|
find_path(PYTHONQT_INCLUDE_DIR PythonQt.h
|
||||||
|
PATHS "${PYTHONQT_INSTALL_DIR}/include/PythonQt"
|
||||||
|
"${PYTHONQT_INSTALL_DIR}/src"
|
||||||
|
DOC "Path to the PythonQt include directory")
|
||||||
|
find_library(PYTHONQT_LIBRARY_RELEASE PythonQt PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "The PythonQt library.")
|
||||||
|
find_library(PYTHONQT_LIBRARY_DEBUG NAMES PythonQt${CTK_CMAKE_DEBUG_POSTFIX} PythonQt${CMAKE_DEBUG_POSTFIX} PythonQt PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "The PythonQt library.")
|
||||||
|
find_library(PYTHONQT_QTALL_LIBRARY_RELEASE PythonQt_QtAll PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "Full Qt bindings for the PythonQt library.")
|
||||||
|
find_library(PYTHONQT_QTALL_LIBRARY_DEBUG NAMES PythonQt_QtAll${CTK_CMAKE_DEBUG_POSTFIX} PythonQt_QtAll${CMAKE_DEBUG_POSTFIX} PythonQt_QtAll PATHS "${PYTHONQT_INSTALL_DIR}/lib" DOC "Full Qt bindings for the PythonQt library.")
|
||||||
|
|
||||||
|
set(PYTHONQT_LIBRARY)
|
||||||
|
|
||||||
|
if(PYTHONQT_LIBRARY_RELEASE)
|
||||||
|
list(APPEND PYTHONQT_LIBRARY optimized ${PYTHONQT_LIBRARY_RELEASE})
|
||||||
|
endif()
|
||||||
|
if(PYTHONQT_LIBRARY_DEBUG)
|
||||||
|
list(APPEND PYTHONQT_LIBRARY debug ${PYTHONQT_LIBRARY_DEBUG})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PYTHONQT_QTALL_LIBRARY)
|
||||||
|
if(PYTHONQT_QTALL_LIBRARY_RELEASE)
|
||||||
|
list(APPEND PYTHONQT_QTALL_LIBRARY optimized ${PYTHONQT_QTALL_LIBRARY_RELEASE})
|
||||||
|
endif()
|
||||||
|
if(PYTHONQT_QTALL_LIBRARY_DEBUG)
|
||||||
|
list(APPEND PYTHONQT_QTALL_LIBRARY debug ${PYTHONQT_QTALL_LIBRARY_DEBUG})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(PYTHONQT_INSTALL_DIR)
|
||||||
|
mark_as_advanced(PYTHONQT_INCLUDE_DIR)
|
||||||
|
mark_as_advanced(PYTHONQT_LIBRARY_RELEASE)
|
||||||
|
mark_as_advanced(PYTHONQT_LIBRARY_DEBUG)
|
||||||
|
mark_as_advanced(PYTHONQT_QTALL_LIBRARY_RELEASE)
|
||||||
|
mark_as_advanced(PYTHONQT_QTALL_LIBRARY_DEBUG)
|
||||||
|
|
||||||
|
# On linux, also find libutil
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
find_library(PYTHONQT_LIBUTIL util)
|
||||||
|
mark_as_advanced(PYTHONQT_LIBUTIL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# All upper case _FOUND variable is maintained for backwards compatibility.
|
||||||
|
set(PYTHONQT_FOUND 0)
|
||||||
|
set(PythonQt_FOUND 0)
|
||||||
|
if(PYTHONQT_INCLUDE_DIR AND PYTHONQT_LIBRARY AND PYTHONQT_QTALL_LIBRARY)
|
||||||
|
# Currently CMake'ified PythonQt only supports building against a python Release build.
|
||||||
|
# This applies independently of CTK build type (Release, Debug, ...)
|
||||||
|
add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK)
|
||||||
|
set(PYTHONQT_FOUND 1)
|
||||||
|
set(PythonQt_FOUND ${PYTHONQT_FOUND})
|
||||||
|
set(PYTHONQT_LIBRARIES ${PYTHONQT_LIBRARY} ${PYTHONQT_LIBUTIL} ${PYTHONQT_QTALL_LIBRARY})
|
||||||
|
endif()
|
@ -1,19 +1,9 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Locate yaml-cpp
|
# Locate yaml-cpp
|
||||||
#
|
#
|
||||||
# This module defines
|
# This module defines
|
||||||
# YAMLCPP_FOUND, if false, do not try to link to yaml-cpp
|
# YAMLCPP_FOUND, if false, do not try to link to yaml-cpp
|
||||||
# YAMLCPP_LIBRARY, where to find yaml-cpp
|
# YAMLCPP_LIBRARY, where to find yaml-cpp
|
||||||
# YAMLCPP_INCLUDE_DIR, where to find yaml.h
|
# YAMLCPP_INCLUDE_DIR, where to find yaml.h
|
||||||
# There is also one IMPORTED library target,
|
|
||||||
# yamlcpp::yamlcpp
|
|
||||||
#
|
#
|
||||||
# By default, the dynamic libraries of yaml-cpp will be found. To find the static ones instead,
|
# By default, the dynamic libraries of yaml-cpp will be found. To find the static ones instead,
|
||||||
# you must set the YAMLCPP_STATIC_LIBRARY variable to TRUE before calling find_package(YamlCpp ...).
|
# you must set the YAMLCPP_STATIC_LIBRARY variable to TRUE before calling find_package(YamlCpp ...).
|
||||||
@ -21,10 +11,6 @@
|
|||||||
# If yaml-cpp is not installed in a standard path, you can use the YAMLCPP_DIR CMake variable
|
# If yaml-cpp is not installed in a standard path, you can use the YAMLCPP_DIR CMake variable
|
||||||
# to tell CMake where yaml-cpp is.
|
# to tell CMake where yaml-cpp is.
|
||||||
|
|
||||||
if(TARGET yamlcpp::yamlcpp)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# attempt to find static library first if this is set
|
# attempt to find static library first if this is set
|
||||||
if(YAMLCPP_STATIC_LIBRARY)
|
if(YAMLCPP_STATIC_LIBRARY)
|
||||||
set(YAMLCPP_STATIC libyaml-cpp.a)
|
set(YAMLCPP_STATIC libyaml-cpp.a)
|
||||||
@ -62,12 +48,3 @@ find_library(YAMLCPP_LIBRARY
|
|||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAMLCPP DEFAULT_MSG YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY)
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAMLCPP DEFAULT_MSG YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY)
|
||||||
mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY)
|
mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY)
|
||||||
|
|
||||||
# Add an imported target
|
|
||||||
if( YAMLCPP_LIBRARY )
|
|
||||||
add_library( yamlcpp::yamlcpp UNKNOWN IMPORTED )
|
|
||||||
set_property( TARGET yamlcpp::yamlcpp PROPERTY IMPORTED_LOCATION ${YAMLCPP_LIBRARY} )
|
|
||||||
if ( YAMLCPP_INCLUDE_DIR )
|
|
||||||
set_property( TARGET yamlcpp::yamlcpp PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${YAMLCPP_INCLUDE_DIR} )
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
182
CMakeModules/GNUInstallDirs.cmake
Normal file
182
CMakeModules/GNUInstallDirs.cmake
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
# - Define GNU standard installation directories
|
||||||
|
# Provides install directory variables as defined for GNU software:
|
||||||
|
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||||
|
# Inclusion of this module defines the following variables:
|
||||||
|
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||||
|
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||||
|
# where <dir> is one of:
|
||||||
|
# BINDIR - user executables (bin)
|
||||||
|
# SBINDIR - system admin executables (sbin)
|
||||||
|
# LIBEXECDIR - program executables (libexec)
|
||||||
|
# SYSCONFDIR - read-only single-machine data (etc)
|
||||||
|
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||||
|
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||||
|
# LIBDIR - object code libraries (lib or lib64)
|
||||||
|
# INCLUDEDIR - C header files (include)
|
||||||
|
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||||
|
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||||
|
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||||
|
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||||
|
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||||
|
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||||
|
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||||
|
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||||
|
# install() commands for the corresponding file type. If the includer does
|
||||||
|
# not define a value the above-shown default will be used and the value will
|
||||||
|
# appear in the cache for editing by the user.
|
||||||
|
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||||
|
# from the corresponding destination by prepending (if necessary) the value
|
||||||
|
# of CMAKE_INSTALL_PREFIX.
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||||
|
# Copyright 2011 Kitware, Inc.
|
||||||
|
#
|
||||||
|
# Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
# see accompanying file Copyright.txt for details.
|
||||||
|
#
|
||||||
|
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the License for more information.
|
||||||
|
#=============================================================================
|
||||||
|
# (To distribute this file outside of CMake, substitute the full
|
||||||
|
# License text for the above reference.)
|
||||||
|
|
||||||
|
# Installation directories
|
||||||
|
#
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||||
|
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||||
|
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||||
|
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||||
|
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||||
|
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||||
|
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||||
|
set(_LIBDIR_DEFAULT "lib")
|
||||||
|
# Override this default 'lib' with 'lib64' iff:
|
||||||
|
# - we are on Linux system but NOT cross-compiling
|
||||||
|
# - we are NOT on debian
|
||||||
|
# - we are on a 64 bits system
|
||||||
|
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||||
|
# Note that the future of multi-arch handling may be even
|
||||||
|
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||||
|
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||||
|
AND NOT CMAKE_CROSSCOMPILING
|
||||||
|
AND NOT EXISTS "/etc/debian_version")
|
||||||
|
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||||
|
message(AUTHOR_WARNING
|
||||||
|
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||||
|
"Please enable at least one language before including GNUInstallDirs.")
|
||||||
|
else()
|
||||||
|
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||||
|
set(_LIBDIR_DEFAULT "lib64")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||||
|
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||||
|
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||||
|
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||||
|
# the cache and store the defaults in local variables if the cache values are
|
||||||
|
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||||
|
|
||||||
|
if(NOT CMAKE_INSTALL_DATADIR)
|
||||||
|
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||||
|
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_INSTALL_INFODIR)
|
||||||
|
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||||
|
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||||
|
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||||
|
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_INSTALL_MANDIR)
|
||||||
|
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||||
|
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||||
|
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||||
|
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mark_as_advanced(
|
||||||
|
CMAKE_INSTALL_BINDIR
|
||||||
|
CMAKE_INSTALL_SBINDIR
|
||||||
|
CMAKE_INSTALL_LIBEXECDIR
|
||||||
|
CMAKE_INSTALL_SYSCONFDIR
|
||||||
|
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||||
|
CMAKE_INSTALL_LOCALSTATEDIR
|
||||||
|
CMAKE_INSTALL_LIBDIR
|
||||||
|
CMAKE_INSTALL_INCLUDEDIR
|
||||||
|
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||||
|
CMAKE_INSTALL_DATAROOTDIR
|
||||||
|
CMAKE_INSTALL_DATADIR
|
||||||
|
CMAKE_INSTALL_INFODIR
|
||||||
|
CMAKE_INSTALL_LOCALEDIR
|
||||||
|
CMAKE_INSTALL_MANDIR
|
||||||
|
CMAKE_INSTALL_DOCDIR
|
||||||
|
)
|
||||||
|
|
||||||
|
# Result directories
|
||||||
|
#
|
||||||
|
foreach(dir
|
||||||
|
BINDIR
|
||||||
|
SBINDIR
|
||||||
|
LIBEXECDIR
|
||||||
|
SYSCONFDIR
|
||||||
|
SHAREDSTATEDIR
|
||||||
|
LOCALSTATEDIR
|
||||||
|
LIBDIR
|
||||||
|
INCLUDEDIR
|
||||||
|
OLDINCLUDEDIR
|
||||||
|
DATAROOTDIR
|
||||||
|
DATADIR
|
||||||
|
INFODIR
|
||||||
|
LOCALEDIR
|
||||||
|
MANDIR
|
||||||
|
DOCDIR
|
||||||
|
)
|
||||||
|
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||||
|
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
@ -1,64 +0,0 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Finds KPMcore and consistently sets API flags based on the version.
|
|
||||||
#
|
|
||||||
# If KPMcore is not found, still create calamares::kpmcore interface
|
|
||||||
# library, which will add definition WITHOUT_KPMcore.
|
|
||||||
#
|
|
||||||
if(NOT TARGET calapmcore)
|
|
||||||
find_package(${kfname}Config CONFIG)
|
|
||||||
find_package(${kfname}I18n CONFIG)
|
|
||||||
find_package(${kfname}WidgetsAddons CONFIG)
|
|
||||||
|
|
||||||
if(WITH_QT6)
|
|
||||||
find_package(KPMcore 24.01.75)
|
|
||||||
else()
|
|
||||||
find_package(KPMcore 20.04.0)
|
|
||||||
endif()
|
|
||||||
set_package_properties(
|
|
||||||
KPMcore
|
|
||||||
PROPERTIES
|
|
||||||
URL "https://invent.kde.org/kde/kpmcore"
|
|
||||||
DESCRIPTION "KDE Partitioning library"
|
|
||||||
TYPE RECOMMENDED
|
|
||||||
PURPOSE "For disk partitioning support"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create an internal Calamares interface to KPMcore
|
|
||||||
# and give it a nice alias name. If kpmcore is not found,
|
|
||||||
# then make a "no KPMcore" library.
|
|
||||||
add_library(calapmcore INTERFACE)
|
|
||||||
|
|
||||||
if(KPMcore_FOUND)
|
|
||||||
find_package(${qtname} REQUIRED DBus) # Needed for KPMCore
|
|
||||||
find_package(${kfname}I18n REQUIRED) # Needed for KPMCore
|
|
||||||
find_package(${kfname}WidgetsAddons REQUIRED) # Needed for KPMCore
|
|
||||||
|
|
||||||
target_link_libraries(calapmcore INTERFACE kpmcore ${qtname}::DBus ${kfname}::I18n ${kfname}::WidgetsAddons)
|
|
||||||
target_include_directories(calapmcore INTERFACE ${KPMCORE_INCLUDE_DIR})
|
|
||||||
# If there were KPMcore API variations, figure them out here
|
|
||||||
# target_compile_definitions(calapmcore INTERFACE WITH_KPMcore)
|
|
||||||
|
|
||||||
# Flag that this library has KPMcore support. A variable
|
|
||||||
# set here has the wrong scope. ENV{} would be visible
|
|
||||||
# everywhere but seems the wrong thing to do. Setting
|
|
||||||
# properties on calapmcore requires a newer CMake than
|
|
||||||
# Debian 11 has, so runs into support issues.
|
|
||||||
add_library(calamares::kpmcore ALIAS calapmcore)
|
|
||||||
else()
|
|
||||||
target_compile_definitions(calapmcore INTERFACE WITHOUT_KPMcore)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
if(TARGET calamares::kpmcore)
|
|
||||||
message(STATUS "KPMcore has already been found")
|
|
||||||
set(KPMcore_FOUND TRUE)
|
|
||||||
else()
|
|
||||||
message(STATUS "KPMcore has been searched-for and not found")
|
|
||||||
set(KPMcore_FOUND FALSE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
157
CMakeModules/MacroLogFeature.cmake
Normal file
157
CMakeModules/MacroLogFeature.cmake
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
# This file defines the Feature Logging macros.
|
||||||
|
#
|
||||||
|
# MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]])
|
||||||
|
# Logs the information so that it can be displayed at the end
|
||||||
|
# of the configure run
|
||||||
|
# VAR : TRUE or FALSE, indicating whether the feature is supported
|
||||||
|
# FEATURE: name of the feature, e.g. "libjpeg"
|
||||||
|
# DESCRIPTION: description what this feature provides
|
||||||
|
# URL: home page
|
||||||
|
# REQUIRED: TRUE or FALSE, indicating whether the featue is required
|
||||||
|
# MIN_VERSION: minimum version number. empty string if unneeded
|
||||||
|
# COMMENTS: More info you may want to provide. empty string if unnecessary
|
||||||
|
#
|
||||||
|
# MACRO_DISPLAY_FEATURE_LOG()
|
||||||
|
# Call this to display the collected results.
|
||||||
|
# Exits CMake with a FATAL error message if a required feature is missing
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# INCLUDE(MacroLogFeature)
|
||||||
|
#
|
||||||
|
# FIND_PACKAGE(JPEG)
|
||||||
|
# MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "")
|
||||||
|
# ...
|
||||||
|
# MACRO_DISPLAY_FEATURE_LOG()
|
||||||
|
|
||||||
|
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
|
||||||
|
# Copyright (c) 2006, Allen Winter, <winter@kde.org>
|
||||||
|
# Copyright (c) 2009, Sebastian Trueg, <trueg@kde.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
IF (NOT _macroLogFeatureAlreadyIncluded)
|
||||||
|
SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
|
||||||
|
IF (EXISTS ${_file})
|
||||||
|
FILE(REMOVE ${_file})
|
||||||
|
ENDIF (EXISTS ${_file})
|
||||||
|
|
||||||
|
SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
|
||||||
|
IF (EXISTS ${_file})
|
||||||
|
FILE(REMOVE ${_file})
|
||||||
|
ENDIF (EXISTS ${_file})
|
||||||
|
|
||||||
|
SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
|
||||||
|
IF (EXISTS ${_file})
|
||||||
|
FILE(REMOVE ${_file})
|
||||||
|
ENDIF (EXISTS ${_file})
|
||||||
|
|
||||||
|
SET(_macroLogFeatureAlreadyIncluded TRUE)
|
||||||
|
|
||||||
|
INCLUDE(FeatureSummary)
|
||||||
|
|
||||||
|
ENDIF (NOT _macroLogFeatureAlreadyIncluded)
|
||||||
|
|
||||||
|
|
||||||
|
MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments)
|
||||||
|
|
||||||
|
STRING(TOUPPER "${ARGV4}" _required)
|
||||||
|
SET(_minvers "${ARGV5}")
|
||||||
|
SET(_comments "${ARGV6}")
|
||||||
|
|
||||||
|
IF (${_var})
|
||||||
|
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
|
||||||
|
ELSE (${_var})
|
||||||
|
IF ("${_required}" STREQUAL "TRUE")
|
||||||
|
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
|
||||||
|
ELSE ("${_required}" STREQUAL "TRUE")
|
||||||
|
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
|
||||||
|
ENDIF ("${_required}" STREQUAL "TRUE")
|
||||||
|
ENDIF (${_var})
|
||||||
|
|
||||||
|
SET(_logtext " * ${_package}")
|
||||||
|
|
||||||
|
IF (NOT ${_var})
|
||||||
|
IF (${_minvers} MATCHES ".*")
|
||||||
|
SET(_logtext "${_logtext} (${_minvers} or higher)")
|
||||||
|
ENDIF (${_minvers} MATCHES ".*")
|
||||||
|
SET(_logtext "${_logtext} <${_url}>\n ")
|
||||||
|
ELSE (NOT ${_var})
|
||||||
|
SET(_logtext "${_logtext} - ")
|
||||||
|
ENDIF (NOT ${_var})
|
||||||
|
|
||||||
|
SET(_logtext "${_logtext}${_description}")
|
||||||
|
|
||||||
|
IF (NOT ${_var})
|
||||||
|
IF (${_comments} MATCHES ".*")
|
||||||
|
SET(_logtext "${_logtext}\n ${_comments}")
|
||||||
|
ENDIF (${_comments} MATCHES ".*")
|
||||||
|
# SET(_logtext "${_logtext}\n") #double-space missing features?
|
||||||
|
ENDIF (NOT ${_var})
|
||||||
|
|
||||||
|
FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n")
|
||||||
|
|
||||||
|
IF(COMMAND SET_PACKAGE_INFO) # in FeatureSummary.cmake since CMake 2.8.3
|
||||||
|
SET_PACKAGE_INFO("${_package}" "\"${_description}\"" "${_url}" "\"${_comments}\"")
|
||||||
|
ENDIF(COMMAND SET_PACKAGE_INFO)
|
||||||
|
|
||||||
|
ENDMACRO(MACRO_LOG_FEATURE)
|
||||||
|
|
||||||
|
|
||||||
|
MACRO(MACRO_DISPLAY_FEATURE_LOG)
|
||||||
|
IF(COMMAND FEATURE_SUMMARY) # in FeatureSummary.cmake since CMake 2.8.3
|
||||||
|
FEATURE_SUMMARY(FILENAME ${CMAKE_CURRENT_BINARY_DIR}/FindPackageLog.txt
|
||||||
|
WHAT ALL)
|
||||||
|
ENDIF(COMMAND FEATURE_SUMMARY)
|
||||||
|
|
||||||
|
SET(_missingFile ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
|
||||||
|
SET(_enabledFile ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
|
||||||
|
SET(_disabledFile ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
|
||||||
|
|
||||||
|
IF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile})
|
||||||
|
SET(_printSummary TRUE)
|
||||||
|
ENDIF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile})
|
||||||
|
|
||||||
|
IF(_printSummary)
|
||||||
|
SET(_missingDeps 0)
|
||||||
|
IF (EXISTS ${_enabledFile})
|
||||||
|
FILE(READ ${_enabledFile} _enabled)
|
||||||
|
FILE(REMOVE ${_enabledFile})
|
||||||
|
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n-----------------------------------------------------------------------------\n${_enabled}")
|
||||||
|
ENDIF (EXISTS ${_enabledFile})
|
||||||
|
|
||||||
|
|
||||||
|
IF (EXISTS ${_disabledFile})
|
||||||
|
SET(_missingDeps 1)
|
||||||
|
FILE(READ ${_disabledFile} _disabled)
|
||||||
|
FILE(REMOVE ${_disabledFile})
|
||||||
|
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n-----------------------------------------------------------------------------\n${_disabled}")
|
||||||
|
ENDIF (EXISTS ${_disabledFile})
|
||||||
|
|
||||||
|
|
||||||
|
IF (EXISTS ${_missingFile})
|
||||||
|
SET(_missingDeps 1)
|
||||||
|
FILE(READ ${_missingFile} _requirements)
|
||||||
|
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- You must install these packages before continuing.\n-----------------------------------------------------------------------------\n${_requirements}")
|
||||||
|
FILE(REMOVE ${_missingFile})
|
||||||
|
SET(_haveMissingReq 1)
|
||||||
|
ENDIF (EXISTS ${_missingFile})
|
||||||
|
|
||||||
|
|
||||||
|
IF (NOT ${_missingDeps})
|
||||||
|
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- Congratulations! All external packages have been found.")
|
||||||
|
ENDIF (NOT ${_missingDeps})
|
||||||
|
|
||||||
|
|
||||||
|
MESSAGE(${_summary})
|
||||||
|
MESSAGE("-----------------------------------------------------------------------------\n")
|
||||||
|
|
||||||
|
|
||||||
|
IF(_haveMissingReq)
|
||||||
|
MESSAGE(FATAL_ERROR "Exiting: Missing Requirements")
|
||||||
|
ENDIF(_haveMissingReq)
|
||||||
|
|
||||||
|
ENDIF(_printSummary)
|
||||||
|
|
||||||
|
ENDMACRO(MACRO_DISPLAY_FEATURE_LOG)
|
48
CMakeModules/MacroOptionalFindPackage.cmake
Normal file
48
CMakeModules/MacroOptionalFindPackage.cmake
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION()
|
||||||
|
# MACRO_OPTIONAL_FIND_PACKAGE( <name> [QUIT] )
|
||||||
|
# This macro is a combination of OPTION() and FIND_PACKAGE(), it
|
||||||
|
# works like FIND_PACKAGE(), but additionally it automatically creates
|
||||||
|
# an option name WITH_<name>, which can be disabled via the cmake GUI.
|
||||||
|
# or via -DWITH_<name>=OFF
|
||||||
|
# The standard <name>_FOUND variables can be used in the same way
|
||||||
|
# as when using the normal FIND_PACKAGE()
|
||||||
|
|
||||||
|
# Copyright (c) 2006-2010 Alexander Neundorf, <neundorf@kde.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
# This is just a helper macro to set a bunch of variables empty.
|
||||||
|
# We don't know whether the package uses UPPERCASENAME or CamelCaseName, so we try both:
|
||||||
|
macro(_MOFP_SET_EMPTY_IF_DEFINED _name _var)
|
||||||
|
if(DEFINED ${_name}_${_var})
|
||||||
|
set(${_name}_${_var} "")
|
||||||
|
endif(DEFINED ${_name}_${_var})
|
||||||
|
|
||||||
|
string(TOUPPER ${_name} _nameUpper)
|
||||||
|
if(DEFINED ${_nameUpper}_${_var})
|
||||||
|
set(${_nameUpper}_${_var} "")
|
||||||
|
endif(DEFINED ${_nameUpper}_${_var})
|
||||||
|
endmacro(_MOFP_SET_EMPTY_IF_DEFINED _package _var)
|
||||||
|
|
||||||
|
|
||||||
|
macro (MACRO_OPTIONAL_FIND_PACKAGE _name )
|
||||||
|
option(WITH_${_name} "Search for ${_name} package" ON)
|
||||||
|
if (WITH_${_name})
|
||||||
|
find_package(${_name} ${ARGN})
|
||||||
|
else (WITH_${_name})
|
||||||
|
string(TOUPPER ${_name} _nameUpper)
|
||||||
|
set(${_name}_FOUND FALSE)
|
||||||
|
set(${_nameUpper}_FOUND FALSE)
|
||||||
|
|
||||||
|
_mofp_set_empty_if_defined(${_name} INCLUDE_DIRS)
|
||||||
|
_mofp_set_empty_if_defined(${_name} INCLUDE_DIR)
|
||||||
|
_mofp_set_empty_if_defined(${_name} INCLUDES)
|
||||||
|
_mofp_set_empty_if_defined(${_name} LIBRARY)
|
||||||
|
_mofp_set_empty_if_defined(${_name} LIBRARIES)
|
||||||
|
_mofp_set_empty_if_defined(${_name} LIBS)
|
||||||
|
_mofp_set_empty_if_defined(${_name} FLAGS)
|
||||||
|
_mofp_set_empty_if_defined(${_name} DEFINITIONS)
|
||||||
|
endif (WITH_${_name})
|
||||||
|
endmacro (MACRO_OPTIONAL_FIND_PACKAGE)
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
<!DOCTYPE RCC>
|
|
||||||
<!-- SPDX-FileCopyrightText: no
|
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
||||||
-->
|
|
||||||
<RCC version="1.0">
|
|
||||||
<qresource prefix="/lang">
|
|
||||||
@calamares_i18n_qrc_content@
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
265
CONTRIBUTING.md
265
CONTRIBUTING.md
@ -1,265 +0,0 @@
|
|||||||
<!-- SPDX-FileCopyrightText: no
|
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Contributing to Calamares
|
|
||||||
|
|
||||||
Welcome to Calamares! We're happy that you would like to add
|
|
||||||
something to Calamares. This contribution guide should help you
|
|
||||||
get started. The guide is not exhaustive: most of it points
|
|
||||||
to other documents that you will need.
|
|
||||||
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
The Calamares community -- of developers, translators, and downstream (distro) users --
|
|
||||||
aims to be courteous, professional, and inclusive. Harrassment, discriminatory
|
|
||||||
statements and abuse are not tolerated. In general, we apply the
|
|
||||||
[KDE Code of Conduct](https://www.kde.org/code-of-conduct/) and the
|
|
||||||
[GNOME Code of Conduct](https://wiki.gnome.org/Foundation/CodeOfConduct) (the
|
|
||||||
rules of decent behavior in both communities are pretty much the same).
|
|
||||||
|
|
||||||
> See the [CoC section on the wiki](https://github.com/calamares/calamares/wiki#code-of-conduct)
|
|
||||||
> for a longer text. To report a problem, please contact the maintainer,
|
|
||||||
> Adriaan de Groot, or the KDE Community Working Group.
|
|
||||||
|
|
||||||
|
|
||||||
## Join the Conversation
|
|
||||||
|
|
||||||
GitHub Issues are **one** place for discussing Calamares if there are concrete
|
|
||||||
problems or a new feature to discuss.
|
|
||||||
Issues are not a help channel.
|
|
||||||
Visit Matrix for help with configuration or compilation.
|
|
||||||
|
|
||||||
Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/)
|
|
||||||
room, `#calamares:kde.org`. Responsiveness is best during the day
|
|
||||||
in Europe, but feel free to idle.
|
|
||||||
Matrix is persistent, and we'll see your message eventually.
|
|
||||||
|
|
||||||
**Note:** You need an account to access Matrix. It doesn't have to be a KDE account,
|
|
||||||
it can be on any Matrix homeserver.
|
|
||||||
|
|
||||||
* [![Join us on Matrix](https://img.shields.io/badge/Matrix-%23calamares:kde.org-blue)](https://webchat.kde.org/#/room/%23calamares:kde.org)
|
|
||||||
|
|
||||||
|
|
||||||
## General Guidelines
|
|
||||||
|
|
||||||
Pull Requests are welcome!
|
|
||||||
|
|
||||||
It is often a good idea to start a Pull Request early, with just work-in-progress,
|
|
||||||
so that the overall approach can be discussed before you put a lot of work
|
|
||||||
into something. Or file an issue describing what you would like to do.
|
|
||||||
|
|
||||||
If you are writing code, stick to the existing coding style and apply
|
|
||||||
the coding-style tool before you commit. It's not my favorite style,
|
|
||||||
but at least all of Calamares is consistent and the tool helps it
|
|
||||||
stay that way.
|
|
||||||
|
|
||||||
If you are writing documentation, use *en_US* spelling.
|
|
||||||
|
|
||||||
If you are doing cool stuff, let us know (on Matrix or through issues).
|
|
||||||
|
|
||||||
**Do** fork Calamares to try new things, **don't** keep your fork to
|
|
||||||
yourself, **do** upstream things as much as you can. When you make cool
|
|
||||||
new things, it's best for the whole Calamares-using-community
|
|
||||||
to build new things that are configurable and applicable to other
|
|
||||||
distributions than your own. So keep other folk in mind. There is
|
|
||||||
also the [extensions](https://github.com/calamares/calamares-extensions)
|
|
||||||
repository for somewhat-more-specialized modules and examples.
|
|
||||||
|
|
||||||
### Commit Messages
|
|
||||||
|
|
||||||
Please try to use `[module] description` as the first line of a commit
|
|
||||||
message. Follow regular git commit-message recommendations: write what
|
|
||||||
and why -- especially the **why** for a change. When modifying a module
|
|
||||||
under `src/modules/`, write the name of the module, e.g. this made-up example:
|
|
||||||
|
|
||||||
```
|
|
||||||
[packages] Enable dnf5 as package-manager
|
|
||||||
|
|
||||||
DNF version 5 prefers the name 'dnf5' to avoid confusion with
|
|
||||||
older DNF, even when a compatibility name 'dnf' is available.
|
|
||||||
```
|
|
||||||
|
|
||||||
It's OK to list multiple modules; don't bother listing a module
|
|
||||||
and its QML variant separately.
|
|
||||||
|
|
||||||
Use `[libcalamares]`, `[libcalamaresui]` and `[calamares]` for changes
|
|
||||||
in those directories as appropriate.
|
|
||||||
|
|
||||||
There are various exceptions, and metadata files follow other conventions.
|
|
||||||
When in doubt, use `git log` to see what kind of **previous** commit messages
|
|
||||||
have been used for a given file.
|
|
||||||
|
|
||||||
### Attribution
|
|
||||||
|
|
||||||
Remember that your git commit contains your git username. This becomes part
|
|
||||||
of the public information in the Calamares repository. There is no way
|
|
||||||
to change this later.
|
|
||||||
|
|
||||||
When you contribute a PR, feel free to add a few lines in the `CHANGES`
|
|
||||||
file, which describes each release. Just add them to the section
|
|
||||||
for the next release, and it can be sorted out when the PR is merged.
|
|
||||||
Remember to add your preferred name in the list of contributors for
|
|
||||||
the release -- names are sorted alphabetically and case-insensitive.
|
|
||||||
|
|
||||||
If you don't add anything to `CHANGES`, don't worry, something will
|
|
||||||
probably be added later in a `Changes: credits` commit.
|
|
||||||
|
|
||||||
> Please do **not** update the `AUTHORS` file. This is done automatically,
|
|
||||||
> but irregularly, based on the git usernames in commits (and some social
|
|
||||||
> knowledge about Calamares contributors).
|
|
||||||
|
|
||||||
|
|
||||||
## Building Calamares
|
|
||||||
|
|
||||||
Up to date
|
|
||||||
[building-Calamares](https://github.com/calamares/calamares/wiki/Develop-Guide)
|
|
||||||
instructions are on the wiki.
|
|
||||||
|
|
||||||
### Simple Build in Docker
|
|
||||||
|
|
||||||
You may have success with the Docker images that the CI system uses.
|
|
||||||
Pick one (or more) of these images which are also used in CI:
|
|
||||||
|
|
||||||
- `docker pull docker://opensuse/tumbleweed`
|
|
||||||
- `docker pull kdeneon/plasma:user`
|
|
||||||
- `docker pull fedora:40`
|
|
||||||
|
|
||||||
See the `nightly-*.yml` files in directory `.github/workflows/` for
|
|
||||||
the full list of Docker images that are used in CI.
|
|
||||||
|
|
||||||
Then start a container with the right image, from the root of Calamares
|
|
||||||
source checkout. Start with this command and substitute `opensuse/tumbleweed`
|
|
||||||
or `kdeneon/plasma:user` for the `$IMAGE` part.
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -ti \
|
|
||||||
--tmpfs /build:rw,exec \
|
|
||||||
--user 0:0 \
|
|
||||||
-e DISPLAY=:0 \
|
|
||||||
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
|
||||||
-v .:/src \
|
|
||||||
$IMAGE \
|
|
||||||
bash
|
|
||||||
```
|
|
||||||
|
|
||||||
This starts a container with the chosen image with a temporary build
|
|
||||||
directory in `/build` and the Calamaressources mounted as `/src`.
|
|
||||||
|
|
||||||
Run the script to install dependencies: you could use `deploycala.py`
|
|
||||||
or one of the shell scripts in `ci/` to install the right
|
|
||||||
dependencies for the image (in this example, for openSUSE and Qt6).
|
|
||||||
- `cd /src`
|
|
||||||
- `./ci/deps-opensuse-qt6.sh`
|
|
||||||
|
|
||||||
Then run CMake (add any CMake options you like at the end) and ninja.
|
|
||||||
- `cmake -S /src -B /build -G Ninja`
|
|
||||||
- `ninja -C /build`
|
|
||||||
|
|
||||||
There is a script `ci/build.sh` that does the CMake an ninja steps.
|
|
||||||
- If you set `CMAKE_ARGS` in the environment those extra CMake options are used.
|
|
||||||
- If you add an argument to the script command which names a workflow
|
|
||||||
(e.g. "nightly-opensuse-qt6") then `CMAKE_ARGS` are extracted from that
|
|
||||||
workflow and used for the build.
|
|
||||||
|
|
||||||
### Running in Docker
|
|
||||||
|
|
||||||
To run Calamares inside the container, or e.g. `loadmodule` to test
|
|
||||||
individual modules, you may need to configure X authentication; a
|
|
||||||
simple and insecure way of doing that is to run `xhost +` in the host
|
|
||||||
environment of the Docker containers.
|
|
||||||
|
|
||||||
To re-use a container (e.g. after exiting it and putting Calamares
|
|
||||||
development away for the night), (re)start the container and connect
|
|
||||||
a shell to it, to continue where you left off. Here, (re)starting
|
|
||||||
a container called *opensuse-qt6*:
|
|
||||||
|
|
||||||
```
|
|
||||||
docker container start opensuse-qt6
|
|
||||||
docker container exec -ti opensuse-qt6 bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dependencies for Calamares 3.3
|
|
||||||
|
|
||||||
> The dependencies for Calamares 3.3 reflect "resonably current"
|
|
||||||
> software as of September 2023. For Calamares 3.2 dependencies,
|
|
||||||
> which are 2017-era, see the `CONTRIBUTING` file in that branch.
|
|
||||||
|
|
||||||
Main:
|
|
||||||
* Compiler with C++17 support
|
|
||||||
* CMake >= 3.16
|
|
||||||
* yaml-cpp >= 0.5.1
|
|
||||||
* Qt >= 5.15 or Qt >= 6.5
|
|
||||||
* KDE Frameworks KCoreAddons >= 5.78
|
|
||||||
* KDE extra-cmake-modules >= 5.78 (recommended; required for some modules;
|
|
||||||
required for some tests)
|
|
||||||
* Python >= 3.6 (required for some modules)
|
|
||||||
* Boost.Python >= 1.72.0 (required for some modules if WITH_PYBIND11 is OFF)
|
|
||||||
|
|
||||||
Individual modules may have their own requirements;
|
|
||||||
these are listed in CMake output.
|
|
||||||
Particular requirements (not complete):
|
|
||||||
|
|
||||||
* *fsresizer* KPMCore >= 20.04
|
|
||||||
* *partition* KPMCore >= 20.04
|
|
||||||
* *users* LibPWQuality (optional)
|
|
||||||
|
|
||||||
|
|
||||||
## Configuring and Deploying Calamares
|
|
||||||
|
|
||||||
[Deployment](https://github.com/calamares/calamares/wiki/Deploy-Guide)
|
|
||||||
instructions are on the wiki.
|
|
||||||
|
|
||||||
|
|
||||||
## Translating Calamares
|
|
||||||
|
|
||||||
Calamares translations are done on Transifex.
|
|
||||||
The [translator's guide](https://github.com/calamares/calamares/wiki/Translate-Guide)
|
|
||||||
on the wiki explains how to get involved there.
|
|
||||||
|
|
||||||
### Using Transifex
|
|
||||||
|
|
||||||
> This section is copied from the wiki. Please read the wiki for more details.
|
|
||||||
|
|
||||||
Calamares uses [Transifex](https://www.transifex.com/) as its translation
|
|
||||||
inrfastructure.
|
|
||||||
The [project overview](https://www.transifex.com/calamares/calamares/) for Calamares
|
|
||||||
shows which languages exist and how translated they are.
|
|
||||||
Translations are (semi-)regularly updated from the *calamares* (development)
|
|
||||||
branch of Calamares and sent to Transifex; updated translations are
|
|
||||||
imported into the same *calamares* branch.
|
|
||||||
|
|
||||||
This means that stable releases don't get translation updates --
|
|
||||||
I have not thought of a good way to do that with one Calamares
|
|
||||||
project in Transifex.
|
|
||||||
|
|
||||||
Internally, the program uses **both** Qt translations and GNU
|
|
||||||
gettext. This is invisible for the translator, but it does mean
|
|
||||||
that the same string can show up in two different Calamares string collections.
|
|
||||||
|
|
||||||
### Using Pull Requests
|
|
||||||
|
|
||||||
> Please avoid using PRs to update translations if you can.
|
|
||||||
> They **can** be merged back to Transifex, but it's somewhat
|
|
||||||
> annoying to do so. You can merge your updated translations files
|
|
||||||
> (the `.ts` files) to Transifex as described in this section.
|
|
||||||
|
|
||||||
- Log in to Transifex
|
|
||||||
- Select the language for upload (e.g. Arabic)
|
|
||||||
- Click the resource to update (e.g. *Calamares* which is the one for the
|
|
||||||
bulk of the strings from the program itself, stored as
|
|
||||||
`lang/calamares_ar.ts` in the repository)
|
|
||||||
- Click *Upload file* and pick the right `.ts` file
|
|
||||||
- Click the *Translate* button to double-check the uploaded translations.
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Calamares
|
|
||||||
|
|
||||||
There is a [testing guide](https://github.com/calamares/calamares/wiki/Test-Guide)
|
|
||||||
on the wiki. It is possible to test most parts of Calamares in isolation,
|
|
||||||
but the real proof of the pudding comes with an actual installation
|
|
||||||
of *some* distro using Calamares.
|
|
||||||
|
|
||||||
The UI components should get some specific usability testing instructions soon.
|
|
||||||
|
|
43
CalamaresAddBrandingSubdirectory.cmake
Normal file
43
CalamaresAddBrandingSubdirectory.cmake
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
include( CMakeColors )
|
||||||
|
|
||||||
|
function( calamares_add_branding_subdirectory )
|
||||||
|
set( SUBDIRECTORY ${ARGV0} )
|
||||||
|
|
||||||
|
if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt" )
|
||||||
|
add_subdirectory( $SUBDIRECTORY )
|
||||||
|
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} branding component: ${BoldRed}${SUBDIRECTORY}${ColorReset}" )
|
||||||
|
|
||||||
|
elseif( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/branding.desc" )
|
||||||
|
set( BRANDING_DIR share/calamares/branding )
|
||||||
|
set( BRANDING_COMPONENT_DESTINATION ${BRANDING_DIR}/${SUBDIRECTORY} )
|
||||||
|
|
||||||
|
if( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" )
|
||||||
|
message( "-- ${BoldYellow}Warning:${ColorReset} branding component ${BoldRed}${SUBDIRECTORY}${ColorReset} has a translations subdirectory but no CMakeLists.txt." )
|
||||||
|
message( "" )
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# We glob all the files inside the subdirectory, and we make sure they are
|
||||||
|
# synced with the bindir structure and installed.
|
||||||
|
file( GLOB BRANDING_COMPONENT_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY} "${SUBDIRECTORY}/*" )
|
||||||
|
foreach( BRANDING_COMPONENT_FILE ${BRANDING_COMPONENT_FILES} )
|
||||||
|
if( NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/${BRANDING_COMPONENT_FILE} )
|
||||||
|
configure_file( ${SUBDIRECTORY}/${BRANDING_COMPONENT_FILE} ${SUBDIRECTORY}/${BRANDING_COMPONENT_FILE} COPYONLY )
|
||||||
|
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${BRANDING_COMPONENT_FILE}
|
||||||
|
DESTINATION ${BRANDING_COMPONENT_DESTINATION} )
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} branding component: ${BoldRed}${SUBDIRECTORY}${ColorReset}" )
|
||||||
|
if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" )
|
||||||
|
message( " ${Green}TYPE:${ColorReset} branding component" )
|
||||||
|
# message( " ${Green}FILES:${ColorReset} ${BRANDING_COMPONENT_FILES}" )
|
||||||
|
message( " ${Green}BRANDING_COMPONENT_DESTINATION:${ColorReset} ${BRANDING_COMPONENT_DESTINATION}" )
|
||||||
|
message( "" )
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message( "-- ${BoldYellow}Warning:${ColorReset} tried to add branding component subdirectory ${BoldRed}${SUBDIRECTORY}${ColorReset} which has no branding.desc." )
|
||||||
|
message( "" )
|
||||||
|
endif()
|
||||||
|
endfunction()
|
@ -1,60 +1,39 @@
|
|||||||
# === This file is part of Calamares - <https://calamares.io> ===
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Calamares is Free Software: see the License-Identifier above.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
###
|
|
||||||
#
|
|
||||||
# Support functions for building plugins.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# calamares_add_library(
|
|
||||||
# library-name
|
|
||||||
# EXPORT_MACRO macro-name
|
|
||||||
# TARGET_TYPE <STATIC|MODULE|...>
|
|
||||||
# EXPORT export-name
|
|
||||||
# VERSION version
|
|
||||||
# SOVERSION version
|
|
||||||
# INSTALL_BINDIR dir
|
|
||||||
# RESOURCES resource-file
|
|
||||||
# SOURCES source-file...
|
|
||||||
# UI ui-file...
|
|
||||||
# LINK_LIBRARIES lib...
|
|
||||||
# LINK_PRIVATE_LIBRARIES lib...
|
|
||||||
# COMPILE_DEFINITIONS def...
|
|
||||||
# [NO_INSTALL]
|
|
||||||
# [NO_VERSION]
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# The COMPILE_DEFINITIONS are set on the resulting module with a suitable
|
|
||||||
# flag (i.e. `-D`) so only state the name (optionally, also the value)
|
|
||||||
# without a `-D` prefixed to it. Pass in a CMake list as needed.
|
|
||||||
include( CMakeParseArguments )
|
include( CMakeParseArguments )
|
||||||
include( CalamaresAutomoc )
|
|
||||||
|
|
||||||
function(calamares_add_library)
|
function(calamares_add_library)
|
||||||
# parse arguments (name needs to be saved before passing ARGN into the macro)
|
# parse arguments (name needs to be saved before passing ARGN into the macro)
|
||||||
set(NAME ${ARGV0})
|
set(NAME ${ARGV0})
|
||||||
set(options NO_INSTALL NO_VERSION)
|
set(options NO_INSTALL NO_VERSION)
|
||||||
set(oneValueArgs NAME EXPORT_MACRO TARGET_TYPE EXPORT VERSION SOVERSION INSTALL_BINDIR RESOURCES)
|
set(oneValueArgs NAME TYPE EXPORT_MACRO TARGET TARGET_TYPE EXPORT VERSION SOVERSION INSTALL_BINDIR RESOURCES)
|
||||||
set(multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS)
|
set(multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS QT5_MODULES)
|
||||||
cmake_parse_arguments(LIBRARY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
cmake_parse_arguments(LIBRARY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
set(LIBRARY_NAME ${NAME})
|
set(LIBRARY_NAME ${NAME})
|
||||||
|
|
||||||
|
|
||||||
|
# message("*** Arguments for ${LIBRARY_NAME}")
|
||||||
|
# message("Sources: ${LIBRARY_SOURCES}")
|
||||||
|
# message("Link libraries: ${LIBRARY_LINK_LIBRARIES}")
|
||||||
|
# message("UI: ${LIBRARY_UI}")
|
||||||
|
# message("TARGET_TYPE: ${LIBRARY_TARGET_TYPE}")
|
||||||
|
# message("EXPORT_MACRO: ${LIBRARY_EXPORT_MACRO}")
|
||||||
|
# message("NO_INSTALL: ${LIBRARY_NO_INSTALL}")
|
||||||
|
|
||||||
set(target ${LIBRARY_NAME})
|
set(target ${LIBRARY_NAME})
|
||||||
|
|
||||||
# qt stuff
|
# qt stuff
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
if(LIBRARY_UI)
|
||||||
|
qt5_wrap_ui(LIBRARY_UI_SOURCES ${LIBRARY_UI})
|
||||||
|
list(APPEND LIBRARY_SOURCES ${LIBRARY_UI_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
# add resources from current dir
|
# add resources from current dir
|
||||||
if(LIBRARY_RESOURCES)
|
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${LIBRARY_RESOURCES}")
|
||||||
list(APPEND LIBRARY_SOURCES ${LIBRARY_RESOURCES})
|
qt5_add_resources(LIBRARY_RC_SOURCES "${LIBRARY_RESOURCES}")
|
||||||
|
list(APPEND LIBRARY_SOURCES ${LIBRARY_RC_SOURCES})
|
||||||
|
unset(LIBRARY_RC_SOURCES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# add target
|
# add target
|
||||||
@ -62,38 +41,35 @@ function(calamares_add_library)
|
|||||||
add_library(${target} STATIC ${LIBRARY_SOURCES})
|
add_library(${target} STATIC ${LIBRARY_SOURCES})
|
||||||
elseif(LIBRARY_TARGET_TYPE STREQUAL "MODULE")
|
elseif(LIBRARY_TARGET_TYPE STREQUAL "MODULE")
|
||||||
add_library(${target} MODULE ${LIBRARY_SOURCES})
|
add_library(${target} MODULE ${LIBRARY_SOURCES})
|
||||||
elseif(LIBRARY_TARGET_TYPE STREQUAL "SHARED")
|
|
||||||
add_library(${target} SHARED ${LIBRARY_SOURCES})
|
|
||||||
else() # default
|
else() # default
|
||||||
message(FATAL_ERROR "Invalid library type '${LIBRARY_TARGET_TYPE}'")
|
add_library(${target} SHARED ${LIBRARY_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
calamares_automoc(${target})
|
# HACK: add qt modules - every lib should define its own set of modules
|
||||||
if(LIBRARY_UI)
|
qt5_use_modules(${target} Core Gui Widgets ${LIBRARY_QT5_MODULES})
|
||||||
calamares_autouic(${target} ${LIBRARY_UI})
|
|
||||||
endif()
|
# definitions - can this be moved into set_target_properties below?
|
||||||
if(LIBRARY_RESOURCES)
|
add_definitions(${QT_DEFINITIONS})
|
||||||
calamares_autorcc(${target} ${LIBRARY_RESOURCES})
|
set_target_properties(${target} PROPERTIES AUTOMOC TRUE)
|
||||||
endif()
|
|
||||||
|
|
||||||
if(LIBRARY_EXPORT_MACRO)
|
if(LIBRARY_EXPORT_MACRO)
|
||||||
set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS ${LIBRARY_EXPORT_MACRO})
|
set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS ${LIBRARY_EXPORT_MACRO})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LIBRARY_COMPILE_DEFINITIONS)
|
if(LIBRARY_COMPILE_DEFINITIONS)
|
||||||
set( _lib_definitions "${LIBRARY_EXPORT_MACRO}" ${LIBRARY_COMPILE_DEFINITIONS} )
|
# Dear CMake, i hate you! Sincerely, domme
|
||||||
set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS "${_lib_definitions}")
|
# At least in CMake 2.8.8, you CANNOT set more than one COMPILE_DEFINITIONS value
|
||||||
|
# only takes the first one if called multiple times or bails out with wrong number of arguments
|
||||||
|
# when passing in a list, thus i redefine the export macro here in hope it won't mess up other targets
|
||||||
|
add_definitions( "-D${LIBRARY_EXPORT_MACRO}" )
|
||||||
|
|
||||||
|
set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS ${LIBRARY_COMPILE_DEFINITIONS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# add link targets
|
# add link targets
|
||||||
target_link_libraries(${target}
|
target_link_libraries(${target} ${CALAMARES_LIBRARIES})
|
||||||
LINK_PUBLIC ${Calamares_LIBRARIES}
|
|
||||||
${qtname}::Core
|
|
||||||
${qtname}::Gui
|
|
||||||
${qtname}::Widgets
|
|
||||||
)
|
|
||||||
if(LIBRARY_LINK_LIBRARIES)
|
if(LIBRARY_LINK_LIBRARIES)
|
||||||
target_link_libraries(${target} LINK_PUBLIC ${LIBRARY_LINK_LIBRARIES})
|
target_link_libraries(${target} ${LIBRARY_LINK_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
if(LIBRARY_LINK_PRIVATE_LIBRARIES)
|
if(LIBRARY_LINK_PRIVATE_LIBRARIES)
|
||||||
target_link_libraries(${target} LINK_PRIVATE ${LIBRARY_LINK_PRIVATE_LIBRARIES})
|
target_link_libraries(${target} LINK_PRIVATE ${LIBRARY_LINK_PRIVATE_LIBRARIES})
|
||||||
@ -118,6 +94,9 @@ function(calamares_add_library)
|
|||||||
set(LIBRARY_INSTALL_LIBDIR "${LIBRARY_INSTALL_BINDIR}")
|
set(LIBRARY_INSTALL_LIBDIR "${LIBRARY_INSTALL_BINDIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#message("INSTALL_BINDIR: ${LIBRARY_INSTALL_BINDIR}")
|
||||||
|
#message("INSTALL_LIBDIR: ${LIBRARY_INSTALL_LIBDIR}")
|
||||||
|
|
||||||
# make installation optional, maybe useful for dummy plugins one day
|
# make installation optional, maybe useful for dummy plugins one day
|
||||||
if(NOT LIBRARY_NO_INSTALL)
|
if(NOT LIBRARY_NO_INSTALL)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
61
CalamaresAddModuleSubdirectory.cmake
Normal file
61
CalamaresAddModuleSubdirectory.cmake
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
include( CMakeColors )
|
||||||
|
|
||||||
|
set( MODULE_DATA_DESTINATION share/calamares/modules )
|
||||||
|
|
||||||
|
function( calamares_add_module_subdirectory )
|
||||||
|
set( SUBDIRECTORY ${ARGV0} )
|
||||||
|
|
||||||
|
# If this subdirectory has a CMakeLists.txt, we add_subdirectory it...
|
||||||
|
if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt" )
|
||||||
|
add_subdirectory( ${SUBDIRECTORY} )
|
||||||
|
# ...otherwise, we look for a module.desc.
|
||||||
|
elseif( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/module.desc" )
|
||||||
|
set( MODULES_DIR ${CMAKE_INSTALL_LIBDIR}/calamares/modules )
|
||||||
|
set( MODULE_DESTINATION ${MODULES_DIR}/${SUBDIRECTORY} )
|
||||||
|
|
||||||
|
# We glob all the files inside the subdirectory, and we make sure they are
|
||||||
|
# synced with the bindir structure and installed.
|
||||||
|
file( GLOB MODULE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY} "${SUBDIRECTORY}/*" )
|
||||||
|
foreach( MODULE_FILE ${MODULE_FILES} )
|
||||||
|
if( NOT IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/${MODULE_FILE} )
|
||||||
|
configure_file( ${SUBDIRECTORY}/${MODULE_FILE} ${SUBDIRECTORY}/${MODULE_FILE} COPYONLY )
|
||||||
|
|
||||||
|
get_filename_component( FLEXT ${MODULE_FILE} EXT )
|
||||||
|
if( "${FLEXT}" STREQUAL ".conf" AND INSTALL_CONFIG)
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
|
||||||
|
DESTINATION ${MODULE_DATA_DESTINATION} )
|
||||||
|
list( APPEND MODULE_CONFIG_FILES ${MODULE_FILE} )
|
||||||
|
else()
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/${MODULE_FILE}
|
||||||
|
DESTINATION ${MODULE_DESTINATION} )
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# We copy over the lang directory, if any
|
||||||
|
if( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" )
|
||||||
|
file( COPY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang"
|
||||||
|
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}" )
|
||||||
|
install( DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${SUBDIRECTORY}/lang"
|
||||||
|
DESTINATION ${MODULE_DESTINATION} )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${SUBDIRECTORY}${ColorReset}" )
|
||||||
|
if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" )
|
||||||
|
message( " ${Green}TYPE:${ColorReset} jobmodule" )
|
||||||
|
# message( " ${Green}FILES:${ColorReset} ${MODULE_FILES}" )
|
||||||
|
message( " ${Green}MODULE_DESTINATION:${ColorReset} ${MODULE_DESTINATION}" )
|
||||||
|
if( MODULE_CONFIG_FILES )
|
||||||
|
if (INSTALL_CONFIG)
|
||||||
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => ${MODULE_DATA_DESTINATION}" )
|
||||||
|
else()
|
||||||
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => [Skipping installation]" )
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
message( "" )
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message( "-- ${BoldYellow}Warning:${ColorReset} tried to add module subdirectory ${BoldRed}${SUBDIRECTORY}${ColorReset} which has no CMakeLists.txt or module.desc." )
|
||||||
|
message( "" )
|
||||||
|
endif()
|
||||||
|
endfunction()
|
97
CalamaresAddPlugin.cmake
Normal file
97
CalamaresAddPlugin.cmake
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
include( CMakeParseArguments )
|
||||||
|
include( ${CALAMARES_CMAKE_DIR}/CalamaresAddLibrary.cmake )
|
||||||
|
|
||||||
|
function( calamares_add_plugin )
|
||||||
|
# parse arguments ( name needs to be saved before passing ARGN into the macro )
|
||||||
|
set( NAME ${ARGV0} )
|
||||||
|
set( options NO_INSTALL SHARED_LIB )
|
||||||
|
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES )
|
||||||
|
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS )
|
||||||
|
cmake_parse_arguments( PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||||
|
set( PLUGIN_NAME ${NAME} )
|
||||||
|
set( PLUGIN_DESTINATION ${CMAKE_INSTALL_LIBDIR}/calamares/modules/${PLUGIN_NAME} )
|
||||||
|
set( PLUGIN_DESC_FILE module.desc )
|
||||||
|
file( GLOB PLUGIN_CONFIG_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.conf" )
|
||||||
|
set( PLUGIN_DATA_DESTINATION share/calamares/modules )
|
||||||
|
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
||||||
|
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
||||||
|
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" )
|
||||||
|
|
||||||
|
include( CMakeColors )
|
||||||
|
message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${PLUGIN_NAME}${ColorReset}" )
|
||||||
|
if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" )
|
||||||
|
message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" )
|
||||||
|
message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" )
|
||||||
|
message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
|
||||||
|
# message( " ${Green}SOURCES:${ColorReset} ${PLUGIN_SOURCES}" )
|
||||||
|
# message( " ${Green}UI:${ColorReset} ${PLUGIN_UI}" )
|
||||||
|
# message( " ${Green}EXPORT_MACRO:${ColorReset} ${PLUGIN_EXPORT_MACRO}" )
|
||||||
|
# message( " ${Green}NO_INSTALL:${ColorReset} ${PLUGIN_NO_INSTALL}" )
|
||||||
|
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
|
||||||
|
if( PLUGIN_CONFIG_FILES )
|
||||||
|
if ( INSTALL_CONFIG )
|
||||||
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${PLUGIN_DATA_DESTINATION}" )
|
||||||
|
else()
|
||||||
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => [Skipping installation]" )
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if( PLUGIN_RESOURCES )
|
||||||
|
message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" )
|
||||||
|
endif()
|
||||||
|
message( "" )
|
||||||
|
endif()
|
||||||
|
# create target name once for convenience
|
||||||
|
set( target "calamares_${PLUGIN_TYPE}_${PLUGIN_NAME}" )
|
||||||
|
|
||||||
|
# determine target type
|
||||||
|
if( NOT ${PLUGIN_SHARED_LIB} )
|
||||||
|
set( target_type "MODULE" )
|
||||||
|
else()
|
||||||
|
set( target_type "SHARED" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list( APPEND calamares_add_library_args
|
||||||
|
"${target}"
|
||||||
|
"EXPORT_MACRO" "${PLUGIN_EXPORT_MACRO}"
|
||||||
|
"TARGET_TYPE" "${target_type}"
|
||||||
|
"SOURCES" "${PLUGIN_SOURCES}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if( PLUGIN_UI )
|
||||||
|
list( APPEND calamares_add_library_args "UI" "${PLUGIN_UI}" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if( PLUGIN_LINK_LIBRARIES )
|
||||||
|
list( APPEND calamares_add_library_args "LINK_LIBRARIES" "${PLUGIN_LINK_LIBRARIES}" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if( PLUGIN_LINK_PRIVATE_LIBRARIES )
|
||||||
|
list( APPEND calamares_add_library_args "LINK_PRIVATE_LIBRARIES" "${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if( PLUGIN_COMPILE_DEFINITIONS )
|
||||||
|
list( APPEND calamares_add_library_args "COMPILE_DEFINITIONS" ${PLUGIN_COMPILE_DEFINITIONS} )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list( APPEND calamares_add_library_args "NO_VERSION" )
|
||||||
|
|
||||||
|
list( APPEND calamares_add_library_args "INSTALL_BINDIR" "${PLUGIN_DESTINATION}" )
|
||||||
|
|
||||||
|
if( PLUGIN_RESOURCES )
|
||||||
|
list( APPEND calamares_add_library_args "RESOURCES" "${PLUGIN_RESOURCES}" )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
calamares_add_library( ${calamares_add_library_args} )
|
||||||
|
|
||||||
|
configure_file( ${PLUGIN_DESC_FILE} ${PLUGIN_DESC_FILE} COPYONLY )
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
||||||
|
DESTINATION ${PLUGIN_DESTINATION} )
|
||||||
|
|
||||||
|
if ( INSTALL_CONFIG )
|
||||||
|
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
|
||||||
|
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE}
|
||||||
|
DESTINATION ${PLUGIN_DATA_DESTINATION} )
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
4
CalamaresBuildTreeSettings.cmake.in
Normal file
4
CalamaresBuildTreeSettings.cmake.in
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(CALAMARES_INCLUDE_DIRS
|
||||||
|
"@PROJECT_SOURCE_DIR@/src/libcalamares"
|
||||||
|
"@PROJECT_BINARY_DIR@/src/libcalamares"
|
||||||
|
)
|
@ -1,104 +1,21 @@
|
|||||||
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
# - Config file for the Calamares package
|
||||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
# It defines the following variables
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# CALAMARES_INCLUDE_DIRS - include directories for Calamares
|
||||||
#
|
# CALAMARES_LIBRARIES - libraries to link against
|
||||||
# Note that Calamares itself is GPL-3.0-or-later: the above license
|
# CALAMARES_EXECUTABLE - the bar executable
|
||||||
# applies to **this** CMake file.
|
|
||||||
#
|
|
||||||
# Config file for the Calamares package
|
|
||||||
#
|
|
||||||
# The following IMPORTED targets are defined:
|
|
||||||
# - Calamares::calamares - the core library
|
|
||||||
# - Calamares::calamaresui - the UI (and QML) library
|
|
||||||
#
|
|
||||||
# For legacy use it defines the following variables:
|
|
||||||
# - Calamares_INCLUDE_DIRS - include directories for Calamares
|
|
||||||
# - Calamares_LIB_DIRS - library directories
|
|
||||||
# - Calamares_LIBRARIES - libraries to link against
|
|
||||||
|
|
||||||
@PACKAGE_INIT@
|
# Compute paths
|
||||||
|
get_filename_component(CALAMARES_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||||
### Versioning and IMPORTED targets
|
if(EXISTS "${CALAMARES_CMAKE_DIR}/CMakeCache.txt")
|
||||||
#
|
# In build tree
|
||||||
#
|
include("${CALAMARES_CMAKE_DIR}/CalamaresBuildTreeSettings.cmake")
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/CalamaresConfigVersion.cmake)
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/CalamaresTargets.cmake)
|
|
||||||
if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui)
|
|
||||||
message(FATAL_ERROR "Calamares found with missing CMake targets")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Need various CMake files that are installed alongside this one.
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
#
|
|
||||||
# The libraries can depend on a variety of Qt and KDE Frameworks
|
|
||||||
# components, so accumulate them and find (just once).
|
|
||||||
#
|
|
||||||
macro(accumulate_deps outvar target namespace)
|
|
||||||
string(LENGTH ${namespace} _nslen)
|
|
||||||
get_target_property(_libs ${target} INTERFACE_LINK_LIBRARIES)
|
|
||||||
foreach(_lib ${_libs})
|
|
||||||
if (_lib MATCHES ^${namespace})
|
|
||||||
string(SUBSTRING ${_lib} ${_nslen} -1 _component)
|
|
||||||
list(APPEND ${outvar} ${_component})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endmacro()
|
|
||||||
|
|
||||||
set(Calamares_WITH_QT6 @WITH_QT6@)
|
|
||||||
if(Calamares_WITH_QT6)
|
|
||||||
set(qtname "Qt6")
|
|
||||||
set(kfname "kf6")
|
|
||||||
message(STATUS "Calamares was built with Qt6 and KDE Frameworks 6")
|
|
||||||
else()
|
else()
|
||||||
set(qtname "Qt5")
|
set(CALAMARES_INCLUDE_DIRS "${CALAMARES_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@/libcalamares")
|
||||||
set(kfname "kf5")
|
|
||||||
message(STATUS "Calamares was built with Qt5 and KDE Frameworks 5 (legacy)")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Qt infrastructure for translations is required
|
# Our library dependencies (contains definitions for IMPORTED targets)
|
||||||
set(qt_required Core Widgets LinguistTools)
|
include("${CALAMARES_CMAKE_DIR}/CalamaresLibraryDepends.cmake")
|
||||||
accumulate_deps(qt_required Calamares::calamares ${qtname}::)
|
|
||||||
accumulate_deps(qt_required Calamares::calamaresui ${qtname}::)
|
|
||||||
find_package(${qtname} CONFIG REQUIRED ${qt_required})
|
|
||||||
|
|
||||||
set(kf_required "")
|
# These are IMPORTED targets created by CalamaresLibraryDepends.cmake
|
||||||
accumulate_deps(kf_required Calamares::calamares ${kfname}::)
|
set(CALAMARES_LIBRARIES calamares)
|
||||||
accumulate_deps(kf_required Calamares::calamaresui ${kfname}::)
|
set(CALAMARES_USE_FILE "${CALAMARES_CMAKE_DIR}/CalamaresUse.cmake")
|
||||||
if(kf_required)
|
|
||||||
find_package(ECM ${ECM_VERSION} NO_MODULE)
|
|
||||||
if( ECM_FOUND )
|
|
||||||
list(INSERT CMAKE_MODULE_PATH 0 ${ECM_MODULE_PATH})
|
|
||||||
find_package(${kfname} REQUIRED COMPONENTS ${kf_required})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(YAMLCPP REQUIRED)
|
|
||||||
|
|
||||||
### Legacy support
|
|
||||||
#
|
|
||||||
#
|
|
||||||
set(Calamares_LIB_DIRS "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
|
|
||||||
set(Calamares_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
|
|
||||||
set(Calamares_LIBRARIES Calamares::calamares)
|
|
||||||
|
|
||||||
### CMake support
|
|
||||||
#
|
|
||||||
#
|
|
||||||
include(CalamaresAddBrandingSubdirectory)
|
|
||||||
include(CalamaresAddLibrary)
|
|
||||||
include(CalamaresAddModuleSubdirectory)
|
|
||||||
include(CalamaresAddPlugin)
|
|
||||||
|
|
||||||
# These are feature-settings that affect consumers of Calamares
|
|
||||||
# libraries as well; without Python-support in the libs, for instance,
|
|
||||||
# there's no point in having a Python plugin.
|
|
||||||
#
|
|
||||||
# This list should match the one in libcalamares/CalamaresConfig.h,
|
|
||||||
# which is the C++-language side of the same configuration.
|
|
||||||
set(Calamares_WITH_PYTHON @WITH_PYTHON@)
|
|
||||||
set(Calamares_WITH_PYBIND11 @WITH_PYBIND11@)
|
|
||||||
set(Calamares_WITH_BOOST_PYTHON @WITH_BOOST_PYTHON@)
|
|
||||||
set(Calamares_WITH_QML @WITH_QML@)
|
|
||||||
set(Calamares_WITH_QT6 @WITH_QT6@)
|
|
||||||
|
12
CalamaresConfigVersion.cmake.in
Normal file
12
CalamaresConfigVersion.cmake.in
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
set(PACKAGE_VERSION "@CALAMARES_VERSION@")
|
||||||
|
|
||||||
|
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||||
|
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
12
CalamaresUse.cmake.in
Normal file
12
CalamaresUse.cmake.in
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#FIXME: this duplicates top level cmakelists: how can we reduce code duplication?
|
||||||
|
|
||||||
|
find_package( Qt5 5.3.0 CONFIG REQUIRED Core Gui Widgets LinguistTools )
|
||||||
|
|
||||||
|
if(NOT CALAMARES_CMAKE_DIR)
|
||||||
|
set(CALAMARES_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include( "${CALAMARES_CMAKE_DIR}/CalamaresAddLibrary.cmake" )
|
||||||
|
include( "${CALAMARES_CMAKE_DIR}/CalamaresAddModuleSubdirectory.cmake" )
|
||||||
|
include( "${CALAMARES_CMAKE_DIR}/CalamaresAddPlugin.cmake" )
|
||||||
|
include( "${CALAMARES_CMAKE_DIR}/CalamaresAddBrandingSubdirectory.cmake" )
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user