├── .gitattributes ├── .github └── workflows │ ├── changelog.json │ ├── commit.yml │ └── main.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── cross-compile-ldd └── make.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.inf binary 2 | -------------------------------------------------------------------------------- /.github/workflows/changelog.json: -------------------------------------------------------------------------------- 1 | { 2 | "categories": [ 3 | { 4 | "title": "ignore", 5 | "labels": ["github"] 6 | }, 7 | { 8 | "title": "## 🪄 OpenMV", 9 | "labels": ["openmv"] 10 | }, 11 | { 12 | "title": "## 🧬 QtCreator", 13 | "labels": ["qtcreator"] 14 | }, 15 | { 16 | "title": "## 📚 Resources", 17 | "labels": ["resources"] 18 | } 19 | ], 20 | "ignore_labels": [ 21 | "github" 22 | ], 23 | "label_extractor": [ 24 | { 25 | "pattern": "^github", 26 | "method": "match", 27 | "on_property": "title" 28 | }, 29 | { 30 | "pattern": "^openmv", 31 | "method": "match", 32 | "on_property": "title" 33 | }, 34 | { 35 | "pattern": "^qtcreator", 36 | "method": "match", 37 | "on_property": "title" 38 | } 39 | ], 40 | "transformers": [ 41 | { 42 | "pattern": "^(.*)\/(.+:.*)", 43 | "target": "- $2" 44 | } 45 | ], 46 | "sort": "DESC", 47 | "template": "${{CHANGELOG}}\n\n## 🪛 Misc Fixes:\n\n${{UNCATEGORIZED}}\n", 48 | "pr_template": "- ${{TITLE}}", 49 | "empty_template": "- no changes", 50 | "max_tags_to_fetch": 100, 51 | "max_pull_requests": 100, 52 | "max_back_track_time_days": 100 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/commit.yml: -------------------------------------------------------------------------------- 1 | name: '📜 Check Commit Messages' 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - reopened 9 | - synchronize 10 | branches: 11 | - 'master' 12 | 13 | jobs: 14 | check-commit-messages: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: '📜 Check commit messages format' 18 | uses: gsactions/commit-message-checker@v2 19 | with: 20 | pattern: '^[^!]+: [A-Za-z]+.+ .+\.$' 21 | flags: 'gm' 22 | error: 'Commit subject line must match the following pattern: : .' 23 | excludeTitle: 'false' 24 | excludeDescription: 'true' 25 | checkAllCommitMessages: 'true' 26 | accessToken: ${{ secrets.GITHUB_TOKEN }} 27 | - name: '📜 Check commit messages length' 28 | uses: gsactions/commit-message-checker@v2 29 | with: 30 | pattern: '^[^#].{10,78}$' 31 | error: 'Commit subject line maximum line length of 78 characters is exceeded.' 32 | excludeTitle: 'false' 33 | excludeDescription: 'true' 34 | checkAllCommitMessages: 'true' 35 | accessToken: ${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: 'CI' 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | branches: 8 | - master 9 | 10 | pull_request: 11 | branches: 12 | - master 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.map.os }} 17 | strategy: 18 | matrix: 19 | # {os: ubuntu-22.04, host: linux-rpi, suffix: tar.gz} 20 | map: [{os: windows-2022, host: windows, suffix: exe}, 21 | {os: windows-2022, host: windows, suffix: zip}, 22 | {os: windows-2022, host: windows-factory, suffix: exe}, 23 | {os: windows-2022, host: windows-factory, suffix: zip}, 24 | {os: ubuntu-22.04, host: linux, suffix: run}, 25 | {os: ubuntu-22.04, host: linux, suffix: tar.gz}, 26 | {os: macos-13, host: mac, suffix: dmg}] 27 | fail-fast: false 28 | steps: 29 | - name: '❖ Fix default line endings on Windows' 30 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 31 | run: git config --global core.autocrlf input 32 | 33 | - name: '⏳ Checkout repository' 34 | uses: actions/checkout@v3 35 | with: 36 | submodules: recursive 37 | 38 | - name: '❖ Install Windows Certificates (1/3)' 39 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 40 | env: 41 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }} 42 | run: | 43 | CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12 44 | echo "$SM_CLIENT_CERT_FILE_B64" | base64 --decode > $CERTIFICATE_PATH 45 | echo "SM_CLIENT_CERT_FILE=$CERTIFICATE_PATH" >> "$GITHUB_ENV" 46 | echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH 47 | echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH 48 | shell: bash 49 | 50 | - name: '❖ Install Windows Certificates (2/3)' 51 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 52 | uses: digicert/ssm-code-signing@v1.0.1 53 | 54 | - name: '❖ Install Windows Certificates (3/3)' 55 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 56 | env: 57 | SM_API_KEY: ${{ secrets.SM_API_KEY }} 58 | run: smctl windows certsync --keypair-alias=$SM_API_KEY 59 | 60 | - name: '🍏 Install Apple Certificates' 61 | if: matrix.map.host == 'mac' 62 | env: 63 | APPLICATION_CERTIFICATE_BASE64: ${{ secrets.MAC_APPLICATION_CER }} 64 | APPLICATION_P12_PASSWORD: ${{ secrets.MAC_APPLICATION_CER_PASSWORD }} 65 | INSTALLER_CERTIFICATE_BASE64: ${{ secrets.MAC_INSTALLER_CER }} 66 | INSTALLER_P12_PASSWORD: ${{ secrets.MAC_INSTALLER_CER_PASSWORD }} 67 | KEYCHAIN_PASSWORD: ${{ secrets.MAC_KEYCHAIN_PASSWORD }} 68 | APPLE_ID: ${{ secrets.MAC_APPLE_ID }} 69 | TEAM_ID: ${{ secrets.MAC_TEAM_ID }} 70 | NOTARYTOOL_PASSWORD: ${{ secrets.MAC_2FA_PASSWORD }} 71 | run: | 72 | KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db 73 | APPLICATION_CERTIFICATE_PATH=$RUNNER_TEMP/application_certificate.p12 74 | INSTALLER_CERTIFICATE_PATH=$RUNNER_TEMP/installer_certificate.p12 75 | echo -n "$APPLICATION_CERTIFICATE_BASE64" | base64 --decode -o $APPLICATION_CERTIFICATE_PATH 76 | echo -n "$INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $INSTALLER_CERTIFICATE_PATH 77 | security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 78 | security set-keychain-settings -lut 21600 $KEYCHAIN_PATH 79 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH 80 | security import $APPLICATION_CERTIFICATE_PATH -P "$APPLICATION_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH 81 | security import $INSTALLER_CERTIFICATE_PATH -P "$INSTALLER_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH 82 | security list-keychain -d user -s $KEYCHAIN_PATH 83 | xcrun notarytool store-credentials "AC_PASSWORD" --apple-id "$APPLE_ID" --team-id "$TEAM_ID" --password "$NOTARYTOOL_PASSWORD" 84 | 85 | - name: '⬇ Install Qt on Windows' 86 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 87 | uses: jurplel/install-qt-action@v4 88 | with: 89 | aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@tools_ifw_fix' 90 | version: '6.5.1' 91 | host: 'windows' 92 | target: 'desktop' 93 | arch: 'win64_mingw' 94 | dir: 'C:\Users\runneradmin' 95 | modules: 'qtimageformats qtserialport qt5compat' 96 | cache: true 97 | tools: 'tools_cmake tools_ifw tools_ninja tools_mingw90' 98 | 99 | - name: '⬇ Install Qt on Linux' 100 | if: matrix.map.host == 'linux' 101 | uses: jurplel/install-qt-action@v4 102 | with: 103 | aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@tools_ifw_fix' 104 | version: '6.5.1' 105 | host: 'linux' 106 | target: 'desktop' 107 | arch: 'gcc_64' 108 | dir: '/home/runner' 109 | modules: 'qtimageformats qtserialport qt5compat' 110 | cache: true 111 | tools: 'tools_cmake tools_ifw tools_ninja' 112 | 113 | - name: '⬇ Install Qt on Mac' 114 | if: matrix.map.host == 'mac' 115 | uses: jurplel/install-qt-action@v4 116 | with: 117 | aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@tools_ifw_fix' 118 | version: '6.5.1' 119 | host: 'mac' 120 | target: 'desktop' 121 | arch: 'clang_64' 122 | dir: '/Users/runner' 123 | modules: 'qtimageformats qtserialport qt5compat' 124 | cache: true 125 | tools: 'tools_cmake tools_ninja' 126 | 127 | - name: '⬇ Install Qt Cross-Compile for Raspberry Pi' 128 | if: matrix.map.host == 'linux-rpi' 129 | run: | 130 | sudo apt-mark hold grub-efi-amd64-signed 131 | sudo apt update --fix-missing -y 132 | sudo apt upgrade -y 133 | sudo apt-get install -y make 134 | sudo apt-get install -y build-essential 135 | sudo apt-get install -y libclang-dev 136 | sudo apt-get install -y ninja-build 137 | sudo apt-get install -y gcc 138 | sudo apt-get install -y git 139 | sudo apt-get install -y bison 140 | sudo apt-get install -y python3 141 | sudo apt-get install -y gperf 142 | sudo apt-get install -y pkg-config 143 | sudo apt-get install -y libfontconfig1-dev 144 | sudo apt-get install -y libfreetype6-dev 145 | sudo apt-get install -y libx11-dev 146 | sudo apt-get install -y libx11-xcb-dev 147 | sudo apt-get install -y libxext-dev 148 | sudo apt-get install -y libxfixes-dev 149 | sudo apt-get install -y libxi-dev 150 | sudo apt-get install -y libxrender-dev 151 | sudo apt-get install -y libxcb1-dev 152 | sudo apt-get install -y libxcb-glx0-dev 153 | sudo apt-get install -y libxcb-keysyms1-dev 154 | sudo apt-get install -y libxcb-image0-dev 155 | sudo apt-get install -y libxcb-shm0-dev 156 | sudo apt-get install -y libxcb-icccm4-dev 157 | sudo apt-get install -y libxcb-sync-dev 158 | sudo apt-get install -y libxcb-xfixes0-dev 159 | sudo apt-get install -y libxcb-shape0-dev 160 | sudo apt-get install -y libxcb-randr0-dev 161 | sudo apt-get install -y libxcb-render-util0-dev 162 | sudo apt-get install -y libxcb-util-dev 163 | sudo apt-get install -y libxcb-xinerama0-dev 164 | sudo apt-get install -y libxcb-xkb-dev 165 | sudo apt-get install -y libxkbcommon-dev 166 | sudo apt-get install -y libxkbcommon-x11-dev 167 | sudo apt-get install -y libatspi2.0-dev 168 | sudo apt-get install -y libgl1-mesa-dev 169 | sudo apt-get install -y libglu1-mesa-dev 170 | sudo apt-get install -y freeglut3-dev 171 | sudo apt-get install -y gcc-aarch64-linux-gnu 172 | sudo apt-get install -y g++-aarch64-linux-gnu 173 | sudo apt-get install -y libclang-11-dev 174 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 175 | sudo apt-get update -y 176 | sudo apt-get upgrade -y libstdc++6 177 | strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX 178 | sudo cp cross-compile-ldd /usr/bin/aarch64-linux-gnu-ldd 179 | cd ~ 180 | wget https://github.com/openmv/qt-raspi/releases/download/v6.5.1/qt-raspi.tar.gz 181 | tar -xzvf qt-raspi.tar.gz 182 | 183 | - name: '🏗 Build IDE on Windows' 184 | if: matrix.map.host == 'windows' && matrix.map.suffix == 'exe' 185 | env: 186 | SM_HOST: ${{ secrets.SM_HOST }} 187 | SM_API_KEY: ${{ secrets.SM_API_KEY }} 188 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} 189 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} 190 | run: python make.py 191 | 192 | - name: '🏗 Build IDE on Windows' 193 | if: matrix.map.host == 'windows' && matrix.map.suffix == 'zip' 194 | env: 195 | SM_HOST: ${{ secrets.SM_HOST }} 196 | SM_API_KEY: ${{ secrets.SM_API_KEY }} 197 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} 198 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} 199 | run: python make.py --no-build-installer 200 | 201 | - name: '🏗 Build IDE on Windows' 202 | if: matrix.map.host == 'windows-factory' && matrix.map.suffix == 'exe' 203 | env: 204 | SM_HOST: ${{ secrets.SM_HOST }} 205 | SM_API_KEY: ${{ secrets.SM_API_KEY }} 206 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} 207 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} 208 | run: python make.py --factory 209 | 210 | - name: '🏗 Build IDE on Windows' 211 | if: matrix.map.host == 'windows-factory' && matrix.map.suffix == 'zip' 212 | env: 213 | SM_HOST: ${{ secrets.SM_HOST }} 214 | SM_API_KEY: ${{ secrets.SM_API_KEY }} 215 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} 216 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }} 217 | run: python make.py --factory --no-build-installer 218 | 219 | - name: '🏗 Build IDE on Linux .run' 220 | if: matrix.map.host == 'linux' && matrix.map.suffix == 'run' 221 | env: 222 | MAKE_ARGS: ${{ matrix.map.make_args }} 223 | run: | 224 | sudo apt-get install -y chrpath 225 | python make.py 226 | version=$(ls build | grep -oP 'openmv-ide-linux-x86_64-\K[0-9]+\.[0-9]+\.[0-9]+(?=\.run)') 227 | cd qt-creator/share/qtcreator 228 | zip -r ../../../build/openmv-ide-resources-${version}.zip examples firmware html models 229 | 230 | - name: '🏗 Build IDE on Linux .tar.gz' 231 | if: matrix.map.host == 'linux' && matrix.map.suffix == 'tar.gz' 232 | env: 233 | MAKE_ARGS: ${{ matrix.map.make_args }} 234 | run: | 235 | sudo apt-get install -y chrpath 236 | python make.py --no-build-installer 237 | 238 | - name: '🏗 Build IDE on Mac' 239 | if: matrix.map.host == 'mac' 240 | run: python make.py 241 | 242 | - name: '🏗 Build IDE on Linux for Raspberry Pi' 243 | if: matrix.map.host == 'linux-rpi' 244 | run: python make.py --rpi ~/qt-raspi 245 | 246 | - name: '⬆ Upload artifacts' 247 | if: github.event_name != 'pull_request' 248 | uses: actions/upload-artifact@v4 249 | with: 250 | name: artifact-${{ matrix.map.os }}-${{ matrix.map.host }}-${{ matrix.map.suffix }} 251 | path: 'build/openmv-*.${{ matrix.map.suffix }}' 252 | if-no-files-found: error 253 | 254 | - name: '⬆ Upload zip' 255 | if: github.event_name != 'pull_request' && ((matrix.map.host == 'linux') && (matrix.map.suffix == 'run')) 256 | uses: actions/upload-artifact@v4 257 | with: 258 | name: artifact-${{ matrix.map.os }}-${{ matrix.map.host }}-${{ matrix.map.suffix }}-zip 259 | path: 'build/openmv-*.zip' 260 | if-no-files-found: error 261 | 262 | - name: '❖ Remove Windows Certificates' 263 | if: matrix.map.host == 'windows' || matrix.map.host == 'windows-factory' 264 | run: rm $SM_CLIENT_CERT_FILE 265 | shell: bash 266 | 267 | - name: '🍏 Remove Apple Certificates' 268 | if: matrix.map.host == 'mac' 269 | run: security delete-keychain $RUNNER_TEMP/app-signing.keychain-db 270 | 271 | stable-release: 272 | needs: build 273 | runs-on: ubuntu-latest 274 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') 275 | steps: 276 | - name: '⏳ Checkout repository' 277 | uses: actions/checkout@v3 278 | with: 279 | submodules: recursive 280 | 281 | - name: "✏️ Generate release changelog" 282 | id: changelog 283 | uses: mikepenz/release-changelog-builder-action@v3 284 | with: 285 | toTag: ${{ github.sha }} 286 | configuration: '.github/workflows/changelog.json' 287 | env: 288 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 289 | 290 | - name: '🔥 Create stable release' 291 | uses: softprops/action-gh-release@v1 292 | with: 293 | draft: true 294 | body: ${{steps.changelog.outputs.changelog}} 295 | env: 296 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 297 | 298 | - name: '📥 Download and upload each artifact separately' 299 | env: 300 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 301 | ACTIONS_STEP_DEBUG: true 302 | run: | 303 | echo "ARTIFACT_NAMES=" >> $GITHUB_ENV 304 | for EXT in zip tar.gz run exe dmg; do 305 | ARTIFACT_PATTERN=artifact-*-$EXT 306 | 307 | echo "Downloading artifacts matching: $ARTIFACT_PATTERN" 308 | gh run download ${{ github.run_id }} -p "$ARTIFACT_PATTERN" 309 | 310 | echo "Uploading to release..." 311 | gh release upload ${{ github.ref_name }} artifact-*-$EXT/* --clobber 312 | 313 | for dir in artifact-*-$EXT; do 314 | echo "Found artifact dir: $dir" 315 | echo "${dir}" >> artifact_names.txt 316 | done 317 | 318 | rm -rf artifact-*-$EXT 319 | done 320 | 321 | echo "ARTIFACT_NAMES<> $GITHUB_ENV 322 | cat artifact_names.txt >> $GITHUB_ENV 323 | echo "EOF" >> $GITHUB_ENV 324 | 325 | - name: '🧹 Remove artifacts' 326 | uses: geekyeggo/delete-artifact@v5 327 | with: 328 | name: ${{ env.ARTIFACT_NAMES }} 329 | failOnError: false 330 | 331 | development-release: 332 | needs: build 333 | runs-on: ubuntu-latest 334 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') == false 335 | permissions: 336 | contents: write 337 | steps: 338 | - name: '⏳ Checkout repository' 339 | uses: actions/checkout@v3 340 | with: 341 | submodules: recursive 342 | 343 | - name: '🧹 Delete old release' 344 | uses: dev-drprasad/delete-tag-and-release@v0.2.1 345 | with: 346 | delete_release: true 347 | tag_name: development 348 | env: 349 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 350 | 351 | - name: "✏️ Generate release changelog" 352 | id: changelog 353 | uses: mikepenz/release-changelog-builder-action@v3 354 | with: 355 | toTag: ${{ github.sha }} 356 | configuration: '.github/workflows/changelog.json' 357 | env: 358 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 359 | 360 | - name: '🔥 Create development release' 361 | uses: softprops/action-gh-release@v1 362 | with: 363 | draft: false 364 | name: Development Release 365 | tag_name: development 366 | body: | 367 | **⚠️ This is a development release, and it may be unstable.** 368 | ${{steps.changelog.outputs.changelog}} 369 | env: 370 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 371 | 372 | - name: '📥 Download and upload each artifact separately' 373 | env: 374 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 375 | ACTIONS_STEP_DEBUG: true 376 | run: | 377 | echo "ARTIFACT_NAMES=" >> $GITHUB_ENV 378 | for EXT in zip tar.gz run exe dmg; do 379 | ARTIFACT_PATTERN=artifact-*-$EXT 380 | 381 | echo "Downloading artifacts matching: $ARTIFACT_PATTERN" 382 | gh run download ${{ github.run_id }} -p "$ARTIFACT_PATTERN" 383 | 384 | echo "Uploading to release..." 385 | gh release upload development artifact-*-$EXT/* --clobber 386 | 387 | for dir in artifact-*-$EXT; do 388 | echo "Found artifact dir: $dir" 389 | echo "${dir}" >> artifact_names.txt 390 | done 391 | 392 | rm -rf artifact-*-$EXT 393 | done 394 | 395 | echo "ARTIFACT_NAMES<> $GITHUB_ENV 396 | cat artifact_names.txt >> $GITHUB_ENV 397 | echo "EOF" >> $GITHUB_ENV 398 | 399 | - name: '🧹 Remove artifacts' 400 | uses: geekyeggo/delete-artifact@v5 401 | with: 402 | name: ${{ env.ARTIFACT_NAMES }} 403 | failOnError: false 404 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | *.autosave 3 | *.pyc 4 | Thumbs.db 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "openmv-media"] 2 | path = openmv-media 3 | url = https://github.com/openmv/openmv-media.git 4 | branch = master 5 | [submodule "qt-creator"] 6 | path = qt-creator 7 | url = https://github.com/openmv/qt-creator.git 8 | branch = openmv-new 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2023 OpenMV 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![IDE Build 🔥](https://github.com/openmv/openmv-ide/actions/workflows/main.yml/badge.svg)](https://github.com/openmv/openmv-ide/actions/workflows/main.yml) 2 | [![GitHub license](https://img.shields.io/github/license/openmv/openmv-ide?label=license%20%E2%9A%96)](https://github.com/openmv/openmv-ide/blob/master/LICENSE) 3 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/openmv/openmv-ide?sort=semver) 4 | [![GitHub forks](https://img.shields.io/github/forks/openmv/openmv-ide?color=green)](https://github.com/openmv/openmv-ide/network) 5 | [![GitHub stars](https://img.shields.io/github/stars/openmv/openmv-ide?color=yellow)](https://github.com/openmv/openmv-ide/stargazers) 6 | [![GitHub issues](https://img.shields.io/github/issues/openmv/openmv-ide?color=orange)](https://github.com/openmv/openmv-ide/issues) 7 | 8 | 9 | 10 | # OpenMV IDE based on Qt Creator 11 | 12 | - [Overview](#overview) 13 | - [Compiling OpenMV IDE for Windows, Linux, and Mac](#compiling-openmv-ide-for-windows-linux-and-mac) 14 | - [Compiling OpenMV IDE for RaspberryPi on Linux](#compiling-openmv-ide-for-raspberrypi-on-linux) 15 | - [Command Line Options](#command-line-options) 16 | - [Instructions for running the installer silently](#instructions-for-running-the-installer-silently) 17 | + [Windows](#windows) 18 | + [Linux](#linux) 19 | + [Mac](#mac) 20 | + [RaspberryPi](#raspberrypi) 21 | - [Contributing to the project](#contributing-to-the-project) 22 | + [Contribution guidelines](#contribution-guidelines) 23 | 24 | ## Overview 25 | 26 | OpenMV IDE is a cross platform integrated development environment for writing python code to run on your OpenMV Cam. It includes all the necessary features and tools to update your OpenMV Cam's firmware and help you develop your application quickly. 27 | 28 | ## Compiling OpenMV IDE for Windows, Linux, and Mac 29 | 30 | Install Qt (to the default location) and then: 31 | 32 | git clone --recursive https://github.com/openmv/openmv-ide.git 33 | cd openmv-ide 34 | ./make.py 35 | 36 | You'll find the installer in `build`. 37 | 38 | ## Compiling OpenMV IDE for RaspberryPi on Linux 39 | 40 | **This guide works for compiling on a `ubuntu-20.04` machine only.** 41 | 42 | First, you need to setup your machine: 43 | 44 | sudo apt update 45 | sudo apt upgrade 46 | 47 | Next you need to download a bunch of packages required for the gui: 48 | 49 | sudo apt-get install make build-essential libclang-dev ninja-build gcc git bison python3 gperf pkg-config libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev libatspi2.0-dev libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev 50 | 51 | Afterwards, you need to install the cross-compiler. Please note that by using `ubuntu-20.04` this command should install version 9 of the cross-compiler. Using a newer version of the operating system will result in a newer version of the cross-compiler which will cause linker mismatch issues between the host system and the RaspberryPi: 52 | 53 | sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu 54 | 55 | Finally, the cmake build system for OpenMV IDE requires libclang to be available on the build system (though it's not used by the IDE): 56 | 57 | sudo apt install libclang-11-dev 58 | 59 | Now it's time to install [Qt Cross-Compiled for the RaspberryPi](https://github.com/openmv/qt-raspi). Please note that this must be installed in your home directory with the username `runner` (e.g. `/home/runner`) as the cross-compile hardcodes its path when it's built: 60 | 61 | cd /home/runner 62 | wget https://github.com/openmv/qt-raspi/releases/download/v6.5.1/qt-raspi.tar.gz 63 | tar -xzvf qt-raspi.tar.gz 64 | 65 | Now we can build the IDE. Please note that you need to install the `cross-compile-ldd` tool before you build as you can see in the snippet below: 66 | 67 | git clone --recursive https://github.com/openmv/openmv-ide.git 68 | cd openmv-ide 69 | sudo cp cross-compile-ldd /usr/bin/aarch64-linux-gnu-ldd 70 | ./make.py --rpi /home/runner/qt-raspi 71 | 72 | You'll find the installer in `build`. 73 | 74 | ## Command Line Options 75 | 76 | Did you know that OpenMV IDE features command line options which allow you to automate connecting to your OpenMV Cam, updating its firmware, running scripts, and more? Pass `-h` or `--help` to OpenMV IDE on the command line to see what you can make the IDE automatically do! 77 | 78 | ## Instructions for running the installer silently 79 | 80 | The Qt Installer Framework features a robust set of command line actions. Using these you can install OpenMV IDE from the command line silently. You can also uninstall the IDE silently using the uninstaller generated by the installer. Please note that the command line installer will not automatically delete an old installation during an upgrade like when in GUI mode. 81 | 82 | ### Windows 83 | 84 | The installer will need administrator privileges which it should ask for when run. 85 | 86 | ./openmv-ide-windows-*.exe --al --am -c in 87 | 88 | And uninstall: 89 | 90 | ./OpenMVIDEUninst.exe --am -c pr 91 | 92 | ### Linux 93 | 94 | Note: `libxcb-xinerama0` may be required for the installer to run. 95 | 96 | ./openmv-ide-linux-x86_64-*.run --al --am -c in 97 | cd 98 | ./setup.sh 99 | 100 | And uninstall: 101 | 102 | sudo ./OpenMVIDEUninstaller --am -c pr 103 | 104 | Alternatively, the installer is a tar file with a setup script: 105 | 106 | tar -xzvf openmv-ide-linux-x86_64-*.tar.gz 107 | cd openmv-ide 108 | ./setup.sh 109 | 110 | And uninstall: 111 | 112 | rm -rf openmv-ide 113 | 114 | ### Mac 115 | 116 | The installer is a DMG with the app inside of it: 117 | 118 | hdiutil attach openmv-ide-mac-*.dmg 119 | sudo cp -rf /Volumes/OpenMV\ IDE/OpenMV\ IDE.app /Applications 120 | sudo hdiutil detach /Volumes/OpenMV\ IDE 121 | 122 | And uninstall: 123 | 124 | sudo rm -rf /Applications/OpenMV\ IDE.app 125 | 126 | ### RaspberryPi 127 | 128 | The installer is a tar file with a setup script: 129 | 130 | tar -xzvf openmv-ide-linux-arm64-*.tar.gz 131 | cd openmv-ide 132 | ./setup.sh 133 | 134 | And uninstall: 135 | 136 | rm -rf openmv-ide 137 | 138 | ## Contributing to the project 139 | 140 | Contributions are most welcome. If you are interested in contributing to the project, start by creating a fork of each of the following repositories: 141 | 142 | * https://github.com/openmv/openmv-ide.git 143 | * https://github.com/openmv/qt-creator.git 144 | 145 | Clone the forked openmv-ide repository, and add a remote to the main openmv-ide repository: 146 | ```bash 147 | git clone --recursive https://github.com//openmv-ide.git 148 | git -C openmv-ide remote add upstream https://github.com/openmv/openmv-ide.git 149 | ``` 150 | 151 | Set the `origin` remote of the qt-creator submodule to the forked qt-creator repo: 152 | ```bash 153 | git -C openmv-ide/qt-creator remote set-url origin https://github.com//qtcreator.git 154 | ``` 155 | 156 | Finally add a remote to openmv's qt-creator fork: 157 | ```bash 158 | git -C openmv-ide/qt-creator remote add upstream https://github.com/openmv/qt-creator.git 159 | ``` 160 | 161 | Now the repositories are ready for pull requests. To send a pull request, create a new feature branch and push it to origin, and use Github to create the pull request from the forked repository to the upstream openmv/qt-creator repository. For example: 162 | ```bash 163 | git checkout -b 164 | 165 | git push origin -u 166 | ``` 167 | 168 | ### Contribution guidelines 169 | Please follow the [best practices](https://developers.google.com/blockly/guides/modify/contribute/write_a_good_pr) when sending pull requests upstream. In general, the pull request should: 170 | * Fix one problem. Don't try to tackle multiple issues at once. 171 | * Split the changes into logical groups using git commits. 172 | * Pull request title should be less than 78 characters, and match this pattern: 173 | * `:<1 space><.>` 174 | * Commit subject line should be less than 78 characters, and match this pattern: 175 | * `:<1 space><.>` 176 | -------------------------------------------------------------------------------- /cross-compile-ldd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ldd drop-in replacement for cross-compilation toolchains. 4 | 5 | # This file is a slightly modified version of xldd.in from 6 | # crosstool-ng 1.22.0 7 | 8 | # In order to use it, copy it in same directory than other 9 | # toolchain binaries and rename it with same tuple. 10 | # (i.e. /opt/arm-sysmic-linux-gnueabihf/bin/arm-sysmic-linux-gnueabihf-ldd) 11 | # Thus, this will automaticaly detect necessary information 12 | # about your toolchain. 13 | 14 | export LC_ALL=C 15 | version="forked from crosstool-ng 1.22.0" 16 | # Change it to 64 if necessary 17 | bits="64" 18 | sed="${SED:-sed}" 19 | grep="${GREP:-grep}" 20 | 21 | my_name="$( basename "${0}" )" 22 | prefix="${0%-ldd}" 23 | gcc="${prefix}-gcc" 24 | readelf="${prefix}-readelf" 25 | fake_load_addr_root="$((0xdeadbeef))" 26 | fake_load_addr_rpath="$((0xdeadc0de))" 27 | fake_load_addr_sysroot="$((0x8badf00d))" 28 | ld_library_path="/lib:/usr/lib" 29 | 30 | do_error() { 31 | printf "%s: %s\n" "${my_name}" "$*" >&2 32 | } 33 | 34 | do_opt_error() { 35 | do_error "$@" 36 | printf "Try \`%s --help' for more information\n" "${my_name}" >&2 37 | } 38 | 39 | do_trace() { 40 | local depth=0 41 | 42 | [ -z "${CT_XLDD_VERBOSE}" ] && return 0 43 | 44 | for((depth=0; "${#FUNCNAME[$((depth+1))]}" != 0; depth++)); do :; done 45 | printf "%*s" $((4*(depth-1))) "" >&2 46 | printf -- "$@" >&2 47 | } 48 | 49 | show_version() { 50 | # Fake a real ldd, just in case some dumb script would check 51 | cat <<_EOF_ 52 | ldd (crosstool-NG) ${version} 53 | Copyright (C) 2010 "Yann E. MORIN" 54 | This is free software; see the source for copying conditions. There is NO 55 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 56 | Licensed under the GPLv2, see the file LICENSES in the top-directory of the 57 | sources for this package. 58 | _EOF_ 59 | } 60 | 61 | show_help() { 62 | cat <<_EOF_ 63 | Usage: ${my_name} [OPTION]... --root DIR FILE... 64 | --help print this help and exit 65 | --version print version information and exit 66 | --root dir treat dir as being the root of the target 67 | -s, --show-system mark libs from the sysroot with a trailing '[*]' 68 | and libs found via RPATH with a trailing '[+]' 69 | _EOF_ 70 | cat <<_EOF_ |fmt 71 | ${my_name} tries to mimick the behavior of a real native ldd, but can be 72 | used in a cross-development environment. Here is how it differs from a 73 | real native ldd: 74 | If the CT_XLDD_VERBOSE variable is set and non-empty, then ${my_name} will 75 | print a lot of debug messages, explaining how it builds the library 76 | search path, and how each library was found and why. 77 | The LD_LIBRARY_PATH variable is not used, as it can not reliably be 78 | guessed except at runtime, and we can't run. 79 | ${my_name} does not scan /etc/ld.so.cache, but instead uses /etc/ld.so.conf 80 | (it understands the include directives therein for libces that have that). 81 | ${my_name} also interprets (tries to!) the RPATH/RUNPATH records found in 82 | the dynamic ELF section. Such paths are searched for only relative to 83 | the specified root, not from the sysroot (see below). Also, those paths 84 | are searched for not only for the file they appear in, but also for its 85 | dependencies. 86 | ${my_name} will search the directory specified with --root for libraries 87 | to resolve the NEEDED tags. If --root is not set, then ${my_name} will 88 | use the value in the environment variable \${CT_XLDD_ROOT}. If neither 89 | is set, then this is an error. 90 | If NEEDED libraries can't be found in the specified root directory, then 91 | ${my_name} will also look in the sysroot of the toolchain to see if it 92 | can find them. 93 | For NEEDED libraries that were found, the output will look like: 94 | libneeded.so => /path/to/libneeded.so (0xloadaddr) 95 | and for those that were not found, the output will look like: 96 | libneeded.so not found 97 | The paths are relative to the specified root directory, or to the sysroot 98 | (eg. /lib/libneeded.so, /usr/lib/libneeded.so, and so on...). 99 | The expected load address 'loadaddr' is a faked address to match the output 100 | of the real ldd, but has no actual meaning (set to some constants for now, 101 | 0x8badf00d for libraries from the sysroot, 0xdeadc0de for those found via 102 | the RPATH/RUNPATH records, and 0xdeadbeef for others). 103 | _EOF_ 104 | 105 | # Unimplemeted yet: 106 | # -d, --data-relocs process data relocations 107 | # -r, --function-relocs process data and function relocations 108 | # -u, --unused print unused direct dependencies 109 | # -v, --verbose print all information 110 | 111 | # See also this thread: 112 | # http://sourceware.org/ml/crossgcc/2008-09/msg00057.html 113 | } 114 | 115 | # Parse command line options 116 | root="${CT_XLDD_ROOT}" 117 | show_system= 118 | while true; do 119 | case "${1}" in 120 | --help) 121 | show_help 122 | exit 0 123 | ;; 124 | --version) 125 | show_version 126 | exit 0 127 | ;; 128 | --root) 129 | root="$2" 130 | shift 131 | ;; 132 | --root=*) 133 | root="${1#--root=}" 134 | ;; 135 | --show-system|-s) 136 | show_system=1 137 | ;; 138 | -*) 139 | do_opt_error "unrecognized option \`${1}'" 140 | exit 1 141 | ;; 142 | *) 143 | break 144 | ;; 145 | esac 146 | shift 147 | done 148 | 149 | # Sanity checks 150 | sysroot="$( "${gcc}" -print-sysroot 2>/dev/null )" 151 | if [ -z "${sysroot}" ]; then 152 | sysroot="$( "${gcc}" -print-file-name=libc.so 2>/dev/null \ 153 | |${sed} -r -e 's:/usr/lib/libc.so$::;' \ 154 | )" 155 | fi 156 | if [ -z "${sysroot}" ]; then 157 | do_error "unable to find sysroot for \`${gcc}'" 158 | fi 159 | 160 | if [ -z "${root}" ]; then 161 | root=${sysroot} 162 | fi 163 | if [ ! -d "${root}" ]; then 164 | do_error "\`${root}': no such file or directory" 165 | exit 1 166 | fi 167 | 168 | do_report_needed_found() { 169 | local needed="${1}" 170 | local path="${2}" 171 | local origin="${3}" 172 | local loadaddr 173 | local sys 174 | 175 | case "${origin}" in 176 | root) 177 | loadaddr="${fake_load_addr_root}" 178 | ;; 179 | rpath) 180 | loadaddr="${fake_load_addr_rpath}" 181 | if [ -n "${show_system}" ]; then 182 | sys=" [+]" 183 | fi 184 | ;; 185 | sysroot) 186 | loadaddr="${fake_load_addr_sysroot}" 187 | if [ -n "${show_system}" ]; then 188 | sys=" [*]" 189 | fi 190 | ;; 191 | esac 192 | 193 | printf "%8s%s => %s (0x%0*x)%s\n" \ 194 | "" \ 195 | "${needed}" \ 196 | "${path}" \ 197 | "$((bits/4))" \ 198 | "${loadaddr}" \ 199 | "${sys}" 200 | } 201 | 202 | # Search a needed file, scanning ${lib_dir} in the root directory 203 | do_find_needed() { 204 | local needed="${1}" 205 | local -a list 206 | local -a dirs 207 | local found 208 | local where 209 | local base 210 | local d i 211 | 212 | do_trace "Searching for '%s'\n" "${needed}" 213 | 214 | # rpath shall come first! 215 | list=( \ 216 | "rpath:${root}" \ 217 | "root:${root}" \ 218 | "sysroot:${sysroot}" \ 219 | ) 220 | 221 | for i in "${list[@]}"; do 222 | where="${i%%:*}" 223 | base="${i#*:}" 224 | if [ "${where}" = "rpath" ]; then 225 | dirs=( "${search_rpath[@]}" ) 226 | else 227 | dirs=( "${needed_search_path[@]}" ) 228 | fi 229 | for d in "${dirs[@]}"; do 230 | do_trace "-> looking in '%s' (%s)\n" "${d}" "${where}" 231 | if [ -f "${base}${d}/${needed}" ]; then 232 | found="${d}/${needed}" 233 | do_trace "---> found\n" 234 | break 2 235 | fi 236 | done 237 | done 238 | 239 | if [ -n "${found}" ]; then 240 | do_report_needed_found "${needed}" "${found}" "${where}" 241 | do_process_file "${base}${found}" 242 | else 243 | printf "%8s%s not found\n" "" "${needed}" 244 | fi 245 | 246 | do_trace "Done searching for '%s'\n" "${needed}" 247 | } 248 | 249 | # Scan a file for all NEEDED tags 250 | do_process_file() { 251 | local file="${1}" 252 | local -a save_search_rpath 253 | local n m 254 | local found 255 | 256 | do_trace "Parsing file '%s'\n" "${file}" 257 | 258 | save_search_rpath=( "${search_rpath[@]}" ) 259 | for n in $( "${readelf}" -d "${file}" \ 260 | |"${grep}" -E '\((RPATH|RUNPATH)\)' \ 261 | |"${sed}" -r -e 's/^.*Library r(|un)path:[[:space:]]+\[(.*)\]$/\2/;'\ 262 | ); do 263 | 264 | OIFS=$IFS; 265 | IFS=":"; 266 | narray=($n) 267 | for subn in "${narray[@]}"; do 268 | do_trace "-> adding rpath '%s'\n" "${subn}" 269 | search_rpath+=( "${subn}" ) 270 | done 271 | IFS=$OIFS; 272 | done 273 | do_trace ": search path:\n" 274 | for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do 275 | do_trace ": - '%s'\n" "${n}" 276 | done 277 | do_trace ": end search path\n" 278 | 279 | for n in $( "${readelf}" -d "${file}" \ 280 | |"${grep}" -E '\(NEEDED\)' \ 281 | |"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[([^]]+)\].*/\1/;' \ 282 | ); do 283 | found=0 284 | for m in "${needed_list[@]}"; do 285 | [ "${n}" = "${m}" ] && found=1 && break 286 | done 287 | if [ ${found} -ne 0 ]; then 288 | do_trace "-> skipping already known dependency '%s'\n" "${n}" 289 | continue 290 | fi 291 | do_trace "-> handling new dependency '%s'\n" "${n}" 292 | needed_list+=( "${n}" ) 293 | do_find_needed "${n}" 294 | do_trace "-> done handling dependency '%s'\n" "${n}" 295 | done 296 | 297 | search_rpath=( "${save_search_rpath[@]}" ) 298 | 299 | do_trace "Finished parsing file '%s'\n" "${file}" 300 | } 301 | 302 | # Recursively scan a /etc/ld.so.conf file 303 | do_scan_etc_ldsoconf() { 304 | local ldsoconf="${1}" 305 | local g 306 | local f 307 | 308 | [ -f "${ldsoconf}" ] || return 0 309 | do_trace "Parsing ld.so.conf: '%s'\n" "${ldsoconf}" 310 | 311 | while read line; do 312 | case "${line}" in 313 | include\ *) 314 | g="${root}${line#include }" 315 | do_trace "-> handling include directive '%s'\n" "${g}" 316 | for f in ${g}; do 317 | do_scan_etc_ldsoconf "${f}" 318 | done 319 | do_trace "-> finished handling include directive '%s'\n" "${g}" 320 | ;; 321 | \#*|"") 322 | ;; 323 | *) 324 | do_trace "-> adding search dir '%s'\n" "${line}" 325 | needed_search_path+=( "${line}" ) 326 | ;; 327 | esac 328 | done <"${ldsoconf}" 329 | 330 | do_trace "Finished parsing ld.so.conf: '%s'\n" "${ldsoconf}" 331 | } 332 | 333 | # Build up the full list of search directories 334 | declare -a needed_search_path 335 | do_trace "Adding basic lib dirs\n" 336 | ld_library_path="${ld_library_path}:" 337 | while [ -n "${ld_library_path}" ]; do 338 | d="${ld_library_path%%:*}" 339 | if [ -n "${d}" ]; then 340 | do_trace "-> adding search dir '%s'\n" "${d}" 341 | needed_search_path+=( "${d}" ) 342 | fi 343 | ld_library_path="${ld_library_path#*:}" 344 | done 345 | do_trace "Done adding basic lib dirs\n" 346 | do_trace "Scanning '/etc/ld.so.conf'\n" 347 | do_scan_etc_ldsoconf "${root}/etc/ld.so.conf" 348 | do_trace "Done scanning '/etc/ld.so.conf'\n" 349 | do_trace "Search path:\n" 350 | for p in "${needed_search_path[@]}"; do 351 | do_trace "-> '%s'\n" "${p}" 352 | done 353 | 354 | declare -a needed_list 355 | declare -a search_rpath 356 | do_trace "Scanning file '%s'\n" "${1}" 357 | do_process_file "${1}" 358 | do_trace "Done scanning file '%s'\n" "${1}" 359 | 360 | -------------------------------------------------------------------------------- /make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # by: Kwabena W. Agyeman - kwagyeman@openmv.io 4 | 5 | import argparse, os, re, shutil, stat, sys 6 | 7 | def match(d0, d1): 8 | x = [x for x in os.listdir(d0) if re.match(d1, x)] 9 | return os.path.join(d0, x[0]) if x else None 10 | 11 | def match_all(d0, d1): 12 | return [os.path.join(d0, x) for x in os.listdir(d0) if re.match(d1, x)] 13 | 14 | def search(d0, d1): 15 | x = [x for x in os.listdir(d0) if re.search(d1, x)] 16 | return os.path.join(d0, x[0]) if x else None 17 | 18 | def search_all(d0, d1): 19 | return [os.path.join(d0, x) for x in os.listdir(d0) if re.search(d1, x)] 20 | 21 | def find_qtdir(rpi): 22 | if rpi: 23 | os.environ["QTDIR"] = rpi 24 | path = os.path.join(rpi, "bin") + ':' 25 | os.environ["PATH"] = path + os.environ["PATH"] 26 | return rpi 27 | elif sys.platform.startswith('win'): 28 | qtdir = match(os.sep, r"Qt") 29 | if qtdir: 30 | qtdir = match(qtdir, r"\d+\.\d+(\.\d+)?") 31 | if qtdir: 32 | qtdir = search(qtdir, r"mingw") 33 | if qtdir: 34 | os.environ["QTDIR"] = qtdir 35 | path = ';' + os.path.join(qtdir, "bin") 36 | os.environ["PATH"] = os.environ["PATH"] + path 37 | return qtdir 38 | qtdir = match(os.path.expanduser('~'), r"Qt") 39 | if qtdir: 40 | qtdir = match(qtdir, r"\d+\.\d+(\.\d+)?") 41 | if qtdir: 42 | qtdir = search(qtdir, r"mingw") 43 | if qtdir: 44 | os.environ["QTDIR"] = qtdir 45 | path = ';' + os.path.join(qtdir, "bin") 46 | os.environ["PATH"] = os.environ["PATH"] + path 47 | return qtdir 48 | elif sys.platform.startswith('darwin'): 49 | qtdir = match(os.path.expanduser('~'), r"Qt") 50 | if qtdir: 51 | qtdir = match(qtdir, r"\d+\.\d+(\.\d+)?") 52 | if qtdir: 53 | qtdir = match(qtdir, r"macos") 54 | if qtdir: 55 | os.environ["QTDIR"] = qtdir 56 | path = ':' + os.path.join(qtdir, "bin") 57 | os.environ["PATH"] = os.environ["PATH"] + path 58 | return qtdir 59 | elif sys.platform.startswith('linux'): 60 | qtdir = match(os.path.expanduser('~'), r"Qt") 61 | if qtdir: 62 | qtdir = match(qtdir, r"\d+\.\d+(\.\d+)?") 63 | if qtdir: 64 | qtdir = search(qtdir, r"gcc") 65 | if qtdir: 66 | os.environ["QTDIR"] = qtdir 67 | path = ':' + os.path.join(qtdir, "bin") 68 | os.environ["PATH"] = os.environ["PATH"] + path 69 | return qtdir 70 | return None 71 | 72 | def find_mingwdir(): 73 | if sys.platform.startswith('win'): 74 | mingwdir = match(os.sep, r"Qt") 75 | if mingwdir: 76 | mingwdir = match(mingwdir, r"Tools") 77 | if mingwdir: 78 | mingwdir = search(mingwdir, r"mingw") 79 | if mingwdir: 80 | os.environ["MINGWDIR"] = mingwdir 81 | path = ';' + os.path.join(mingwdir, "bin") 82 | os.environ["PATH"] = os.environ["PATH"] + path 83 | return mingwdir 84 | mingwdir = match(os.path.expanduser('~'), r"Qt") 85 | if mingwdir: 86 | mingwdir = match(mingwdir, r"Tools") 87 | if mingwdir: 88 | mingwdir = search(mingwdir, r"mingw") 89 | if mingwdir: 90 | os.environ["MINGWDIR"] = mingwdir 91 | path = ';' + os.path.join(mingwdir, "bin") 92 | os.environ["PATH"] = os.environ["PATH"] + path 93 | return mingwdir 94 | return None 95 | 96 | def find_cmakedir(): 97 | if sys.platform.startswith('win'): 98 | cmakedir = match(os.sep, r"Qt") 99 | if cmakedir: 100 | cmakedir = match(cmakedir, r"Tools") 101 | if cmakedir: 102 | cmakedir = search(cmakedir, r"CMake") 103 | if cmakedir: 104 | os.environ["CMAKEDIR"] = cmakedir 105 | path = ';' + os.path.join(cmakedir, "bin") 106 | os.environ["PATH"] = os.environ["PATH"] + path 107 | return cmakedir 108 | cmakedir = match(os.path.expanduser('~'), r"Qt") 109 | if cmakedir: 110 | cmakedir = match(cmakedir, r"Tools") 111 | if cmakedir: 112 | cmakedir = search(cmakedir, r"CMake") 113 | if cmakedir: 114 | os.environ["CMAKEDIR"] = cmakedir 115 | path = ';' + os.path.join(cmakedir, "bin") 116 | os.environ["PATH"] = os.environ["PATH"] + path 117 | return cmakedir 118 | elif sys.platform.startswith('darwin'): 119 | cmakedir = match(os.path.expanduser('~'), r"Qt") 120 | if cmakedir: 121 | cmakedir = match(cmakedir, r"Tools") 122 | if cmakedir: 123 | cmakedir = match(cmakedir, r"CMake") 124 | if cmakedir: 125 | cmakedir = match(cmakedir, r"CMake.app") 126 | if cmakedir: 127 | cmakedir = match(cmakedir, r"Contents") 128 | if cmakedir: 129 | os.environ["CMAKEDIR"] = cmakedir 130 | path = ':' + os.path.join(cmakedir, "bin") 131 | os.environ["PATH"] = os.environ["PATH"] + path 132 | return cmakedir 133 | elif sys.platform.startswith('linux'): 134 | cmakedir = match(os.path.expanduser('~'), r"Qt") 135 | if cmakedir: 136 | cmakedir = match(cmakedir, r"Tools") 137 | if cmakedir: 138 | cmakedir = search(cmakedir, r"CMake") 139 | if cmakedir: 140 | os.environ["CMAKEDIR"] = cmakedir 141 | path = ':' + os.path.join(cmakedir, "bin") 142 | os.environ["PATH"] = os.environ["PATH"] + path 143 | return cmakedir 144 | return None 145 | 146 | def find_ninjadir(): 147 | if sys.platform.startswith('win'): 148 | ninjadir = match(os.sep, r"Qt") 149 | if ninjadir: 150 | ninjadir = match(ninjadir, r"Tools") 151 | if ninjadir: 152 | ninjadir = match(ninjadir, r"Ninja") 153 | if ninjadir: 154 | os.environ["NINJADIR"] = ninjadir 155 | path = ';' + ninjadir 156 | os.environ["PATH"] = os.environ["PATH"] + path 157 | return ninjadir 158 | ninjadir = match(os.path.expanduser('~'), r"Qt") 159 | if ninjadir: 160 | ninjadir = match(ninjadir, r"Tools") 161 | if ninjadir: 162 | ninjadir = match(ninjadir, r"Ninja") 163 | if ninjadir: 164 | os.environ["NINJADIR"] = ninjadir 165 | path = ';' + ninjadir 166 | os.environ["PATH"] = os.environ["PATH"] + path 167 | return ninjadir 168 | elif sys.platform.startswith('darwin'): 169 | ninjadir = match(os.path.expanduser('~'), r"Qt") 170 | if ninjadir: 171 | ninjadir = match(ninjadir, r"Tools") 172 | if ninjadir: 173 | ninjadir = match(ninjadir, r"Ninja") 174 | if ninjadir: 175 | os.environ["NINJADIR"] = ninjadir 176 | path = ':' + ninjadir 177 | os.environ["PATH"] = os.environ["PATH"] + path 178 | return ninjadir 179 | elif sys.platform.startswith('linux'): 180 | ninjadir = match(os.path.expanduser('~'), r"Qt") 181 | if ninjadir: 182 | ninjadir = match(ninjadir, r"Tools") 183 | if ninjadir: 184 | ninjadir = match(ninjadir, r"Ninja") 185 | if ninjadir: 186 | os.environ["NINJADIR"] = ninjadir 187 | path = ':' + ninjadir 188 | os.environ["PATH"] = os.environ["PATH"] + path 189 | return ninjadir 190 | return None 191 | 192 | def find_ifdir(): 193 | if sys.platform.startswith('win'): 194 | ifdir = match(os.sep, r"Qt") 195 | if ifdir: 196 | ifdir = match(ifdir, r"Tools") 197 | if ifdir: 198 | ifdir = match(ifdir, r"QtInstallerFramework") 199 | if ifdir: 200 | ifdir = match(ifdir, r"\d+\.\d+(\.\d+)?") 201 | if ifdir: 202 | os.environ["IFDIR"] = ifdir 203 | path = ';' + os.path.join(ifdir, "bin") 204 | os.environ["PATH"] = os.environ["PATH"] + path 205 | return ifdir 206 | ifdir = match(os.path.expanduser('~'), r"Qt") 207 | if ifdir: 208 | ifdir = match(ifdir, r"Tools") 209 | if ifdir: 210 | ifdir = match(ifdir, r"QtInstallerFramework") 211 | if ifdir: 212 | ifdir = match(ifdir, r"\d+\.\d+(\.\d+)?") 213 | if ifdir: 214 | os.environ["IFDIR"] = ifdir 215 | path = ';' + os.path.join(ifdir, "bin") 216 | os.environ["PATH"] = os.environ["PATH"] + path 217 | return ifdir 218 | elif sys.platform.startswith('darwin'): 219 | ifdir = match(os.path.expanduser('~'), r"Qt") 220 | if ifdir: 221 | ifdir = search(ifdir, r"QtIFW") 222 | if ifdir: 223 | os.environ["IFDIR"] = ifdir 224 | path = ':' + os.path.join(ifdir, "bin") 225 | os.environ["PATH"] = os.environ["PATH"] + path 226 | return ifdir 227 | elif sys.platform.startswith('linux'): 228 | ifdir = match(os.path.expanduser('~'), r"Qt") 229 | if ifdir: 230 | ifdir = match(ifdir, r"Tools") 231 | if ifdir: 232 | ifdir = match(ifdir, r"QtInstallerFramework") 233 | if ifdir: 234 | ifdir = match(ifdir, r"\d+\.\d+(\.\d+)?") 235 | if ifdir: 236 | os.environ["IFDIR"] = ifdir 237 | path = ':' + os.path.join(ifdir, "bin") 238 | os.environ["PATH"] = os.environ["PATH"] + path 239 | return ifdir 240 | return None 241 | 242 | def find_windowssdkdir(): 243 | if sys.platform.startswith('win'): 244 | windowssdkdir = match(os.sep, r"Program Files \(x86\)") 245 | if windowssdkdir: 246 | windowssdkdir = match(windowssdkdir, r"Windows Kits") 247 | if windowssdkdir: 248 | windowssdkdir = match(windowssdkdir, r"10") 249 | if windowssdkdir: 250 | windowssdkdir = match(windowssdkdir, r"bin") 251 | if windowssdkdir: 252 | for d in match_all(windowssdkdir, r"\d+\.\d+\.\d+\.\d+"): 253 | dx64 = match(d, r"x64") 254 | if dx64: 255 | dx64exe = match(dx64, r"signtool.exe") 256 | if dx64exe: 257 | os.environ["WINDOWSSDKDIR"] = dx64 258 | path = ';' + os.path.join(dx64) 259 | os.environ["PATH"] = os.environ["PATH"] + path 260 | return dx64 261 | dx86 = match(d, r"x86") 262 | if dx86: 263 | dx86exe = match(dx86, r"signtool.exe") 264 | if dx86exe: 265 | os.environ["WINDOWSSDKDIR"] = dx86 266 | path = ';' + os.path.join(dx86) 267 | os.environ["PATH"] = os.environ["PATH"] + path 268 | return dx86 269 | return None 270 | 271 | def get_ideversion(folder): 272 | for line in reversed(list(open(os.path.join(folder, "qt-creator/cmake/QtCreatorIDEBranding.cmake")))): 273 | match = re.search(r'set\(IDE_VERSION\s+"([^"]+)"\)', line) 274 | if match: return match.group(1) 275 | 276 | def make(): 277 | 278 | __folder__ = os.path.dirname(os.path.abspath(__file__)) 279 | 280 | parser = argparse.ArgumentParser(description = 281 | "Make Script") 282 | 283 | parser.add_argument("--rpi", nargs = '?', 284 | help = "Qt 6 Cross-Compile QTDIR for the Raspberry Pi") 285 | 286 | parser.add_argument("--no-build-application", action='store_true', default=False, 287 | help = "Don't build the application") 288 | 289 | parser.add_argument("--no-sign-application", action='store_true', default=False, 290 | help = "Don't sign the application on windows and mac") 291 | 292 | parser.add_argument("--no-build-installer", action='store_true', default=False, 293 | help = "Don't build the installer") 294 | 295 | parser.add_argument("--no-sign-installer", action='store_true', default=False, 296 | help = "Don't sign the installer on windows and mac") 297 | 298 | parser.add_argument("--factory", action='store_true', default=False, 299 | help = "Build OpenMV IDE for the factory") 300 | 301 | args = parser.parse_args() 302 | 303 | if args.rpi and not sys.platform.startswith('linux'): 304 | sys.exit("Linux Only") 305 | 306 | ########################################################################### 307 | 308 | qtdir = find_qtdir(args.rpi) 309 | mingwdir = find_mingwdir() 310 | find_cmakedir() 311 | find_ninjadir() 312 | ifdir = find_ifdir() 313 | find_windowssdkdir() 314 | 315 | ideversion = get_ideversion(__folder__) 316 | 317 | builddir = os.path.join(__folder__, "build") 318 | installdir = os.path.join(builddir, "install") 319 | if args.rpi: installdir = os.path.join(builddir, "openmv-ide") 320 | 321 | if not os.path.exists(builddir): 322 | os.mkdir(builddir) 323 | 324 | if not os.path.exists(installdir): 325 | os.mkdir(installdir) 326 | 327 | cxx_flags_init = "" 328 | 329 | if args.factory: 330 | cxx_flags_init += "-DFORCE_FORM_KEY_DIALOG " 331 | cxx_flags_init += "-DFORCE_AUTO_CONNECT " 332 | cxx_flags_init += "-DFORCE_AUTO_UPDATE=release " 333 | cxx_flags_init += "-DFORCE_AUTO_RUN " 334 | cxx_flags_init += "-DFORCE_OVERRIDE_READ_TIMEOUT=3000 " 335 | 336 | if args.rpi: 337 | installer_name = "openmv-ide-linux-arm64-" + ideversion + ".tar.gz" 338 | if args.factory: installer_name = installer_name.replace("openmv", "openmv-factory") 339 | if not args.no_build_application: 340 | os.makedirs(os.path.join(installdir, "lib/Qt/lib"), exist_ok=True) 341 | if os.system("cd " + builddir + 342 | " && wget http://ftp.us.debian.org/debian/pool/main/i/icu/libicu67_67.1-7_arm64.deb" 343 | " && dpkg-deb -x libicu67_67.1-7_arm64.deb icu67" 344 | " && cp -rv icu67/usr/lib/aarch64-linux-gnu/* openmv-ide/lib/Qt/lib/" 345 | " && cmake ../qt-creator -Wno-dev" + 346 | " \"-DCMAKE_GENERATOR:STRING=Ninja\"" + 347 | " \"-DCMAKE_BUILD_TYPE:STRING=Release\"" + 348 | " \"-DCMAKE_PREFIX_PATH:PATH=" + qtdir + "\"" + 349 | " \"-DCMAKE_C_COMPILER:FILEPATH=/usr/bin/aarch64-linux-gnu-gcc-9\"" + 350 | " \"-DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/aarch64-linux-gnu-g++-9\"" + 351 | " \"-DCMAKE_CXX_FLAGS_INIT:STRING=" + cxx_flags_init + "\"" + 352 | " \"-DCMAKE_TOOLCHAIN_FILE:UNINITIALIZED=" + os.path.join(qtdir, "lib/cmake/Qt6/qt.toolchain.cmake") + "\"" + 353 | " && cmake --build . --target all" + 354 | " && cmake --install . --prefix openmv-ide" + 355 | " && cmake --install . --prefix openmv-ide --component Dependencies" + 356 | " && mv share/qtcreator/arm install/share/qtcreator/arm" + 357 | " && mv share/qtcreator/stedgeai install/share/qtcreator/stedgeai" + 358 | " && rm -rf bin" + # Save disk space 359 | " && rm -rf lib" + # Save disk space 360 | " && rm -rf share" + # Save disk space 361 | " && rm -rf src"): # Save disk space 362 | sys.exit("Make Failed...") 363 | if not args.no_build_installer: 364 | with open(os.path.join(installdir, "README.txt"), 'w') as f: 365 | f.write("Please run setup.sh to install OpenMV IDE dependencies:\n\n") 366 | f.write(" ./setup.sh\n\n") 367 | f.write("And then run OpenMV IDE:\n\n") 368 | f.write(" ./bin/openmvide\n") 369 | with open(os.path.join(installdir, "setup.sh"), 'w') as f: 370 | f.write("#! /bin/sh\n\n") 371 | f.write("DIR=\"$(dirname \"$(readlink -f \"$0\")\")\"\n\n") 372 | f.write("sudo apt-get update -y\n") 373 | f.write("sudo apt-get full-upgrade -y\n") 374 | f.write("sudo apt-get install -y libboost-all-dev libudev-dev libinput-dev libts-dev libmtdev-dev libjpeg-dev libfontconfig1-dev libssl-dev libdbus-1-dev libglib2.0-dev libxkbcommon-dev libegl1-mesa-dev libgbm-dev libgles2-mesa-dev mesa-common-dev libasound2-dev libpulse-dev gstreamer1.0-omx libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-alsa libvpx-dev libsrtp2-dev libsnappy-dev libnss3-dev \"^libxcb.*\" flex bison libxslt-dev ruby gperf libbz2-dev libcups2-dev libatkmm-1.6-dev libxi6 libxcomposite1 libfreetype6-dev libicu-dev libsqlite3-dev libxslt1-dev libavcodec-dev libavformat-dev libswscale-dev libx11-dev freetds-dev libsqlite3-dev libpq-dev libiodbc2-dev firebird-dev libgst-dev libxext-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync1 libxcb-sync-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxi-dev libdrm-dev libxcb-xinerama0 libxcb-xinerama0-dev libatspi2.0-dev libxcursor-dev libxcomposite-dev libxdamage-dev libxss-dev libxtst-dev libpci-dev libcap-dev libxrandr-dev libdirectfb-dev libaudio-dev libxkbcommon-x11-dev libxcb-cursor0 build-essential\n\n") 375 | f.write("sudo apt-get install -y libpng16-16 libusb-1.0 python3 python3-pip python3-usb\n") 376 | f.write("sudo cp $DIR/share/qtcreator/pydfu/*.rules /etc/udev/rules.d/\n") 377 | f.write("sudo udevadm trigger\n") 378 | f.write("sudo udevadm control --reload-rules\n\n") 379 | f.write("cp -r \"$DIR/share/icons\" \"/home/$USER/.local/share/icons\"\n") 380 | f.write("sudo cp -r \"$DIR/share/icons\" /usr/share/\n") 381 | f.write("rm -rf \"$DIR/share/icons\"\n") 382 | f.write("sudo gtk-update-icon-cache\n\n") 383 | f.write("cat > \"/home/$USER/Desktop/openmvide.desktop\" << EOM\n") 384 | f.write("[Desktop Entry]\n") 385 | f.write("Type=Application\n") 386 | f.write("Name=OpenMV IDE\n") 387 | f.write("GenericName=OpenMV IDE\n") 388 | f.write("Comment=The IDE of choice for OpenMV Cam Development.\n") 389 | f.write("Exec=\"$DIR/bin/openmvide\" %F\n") 390 | f.write("Icon=OpenMV-openmvide\n") 391 | f.write("Terminal=false\n") 392 | f.write("Categories=Development;IDE;Electronics;OpenMV;\n") 393 | f.write("MimeType=text/x-python;\n") 394 | f.write("Keywords=embedded electronics;electronics;microcontroller;micropython;computer vision;machine vision;\n") 395 | f.write("StartupWMClass=openmvide\n") 396 | f.write("EOM\n") 397 | f.write("cp \"/home/$USER/Desktop/openmvide.desktop\" \"/home/$USER/.local/share/applications/\"\n") 398 | f.write("sudo cp \"/home/$USER/Desktop/openmvide.desktop\" /usr/share/applications/\n") 399 | os.chmod(os.path.join(installdir, "setup.sh"), 400 | os.stat(os.path.join(installdir, "setup.sh")).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 401 | if os.system("cd " + builddir + 402 | " && tar -czvf " + installer_name + " openmv-ide"): 403 | sys.exit("Make Failed...") 404 | 405 | elif sys.platform.startswith('win'): 406 | installer_name = "openmv-ide-windows-" + ideversion 407 | if args.factory: installer_name = installer_name.replace("openmv", "openmv-factory") 408 | installer_archive_name = installer_name + "-installer-archive.7z" 409 | if not args.no_build_application: 410 | if os.system("cd " + builddir + 411 | " && cmake ../qt-creator" + 412 | " \"-DCMAKE_GENERATOR:STRING=Ninja\"" + 413 | " \"-DCMAKE_BUILD_TYPE:STRING=Release\"" + 414 | " \"-DQT_QMAKE_EXECUTABLE:FILEPATH=" + os.path.join(qtdir, "bin/qmake.exe") + "\"" + 415 | " \"-DCMAKE_PREFIX_PATH:PATH=" + qtdir + "\"" + 416 | " \"-DCMAKE_C_COMPILER:FILEPATH=" + os.path.join(mingwdir, "bin/gcc.exe") + "\"" + 417 | " \"-DCMAKE_CXX_COMPILER:FILEPATH=" + os.path.join(mingwdir, "bin/g++.exe") + "\"" + 418 | " \"-DCMAKE_CXX_FLAGS_INIT:STRING=" + cxx_flags_init + "\"" + 419 | " && cmake --build . --target all" + 420 | " && cmake --install . --prefix install" + 421 | " && cmake --install . --prefix install --component Dependencies" + 422 | " && mv share/qtcreator/arm install/share/qtcreator/arm" + 423 | " && mv share/qtcreator/stedgeai install/share/qtcreator/stedgeai" + 424 | " && rm -rf bin" + # Save disk space 425 | " && rm -rf lib" + # Save disk space 426 | " && rm -rf share" + # Save disk space 427 | " && rm -rf src"): # Save disk space 428 | sys.exit("Make Failed...") 429 | if not args.no_sign_application: 430 | if os.system("cd " + builddir + 431 | " && python -u ../qt-creator/scripts/sign.py install/bin/openmvide.exe"): 432 | sys.exit("Make Failed...") 433 | if not args.no_build_installer: 434 | if os.system("cd " + builddir + 435 | " && cd install" + 436 | " && archivegen ../" + installer_archive_name + " bin lib share" + 437 | " && cd .." 438 | " && python -u ../qt-creator/scripts/packageIfw.py -i " + ifdir + 439 | " -v " + ideversion + 440 | " -a " + installer_archive_name + " " + installer_name): 441 | sys.exit("Make Failed...") 442 | if not args.no_sign_installer: 443 | if os.system("cd " + builddir + 444 | " && python -u ../qt-creator/scripts/sign.py " + installer_name + ".exe"): 445 | sys.exit("Make Failed...") 446 | else: 447 | with open(os.path.join(installdir, "README.txt"), 'w') as f: 448 | f.write("Please run setup.cmd to install OpenMV IDE's drivers:\r\n\r\n") 449 | f.write(" Double click on setup.cmd\r\n\r\n") 450 | f.write("And then to run OpenMV IDE:\r\n\r\n") 451 | f.write(" Double click on bin\\openmvide.exe\r\n") 452 | with open(os.path.join(installdir, "setup.cmd"), 'w') as f: 453 | f.write("@echo off\r\n") 454 | f.write("NET FILE 1>NUL 2>NUL & IF ERRORLEVEL 1 (ECHO You must right-click this file and select \"Run as administrator\" to run the setup script. & ECHO. & PAUSE & EXIT /D)\r\n") 455 | f.write("cmd /c \"%~dp0\\share\\qtcreator\\drivers\\ftdi\\ftdi.cmd\"\r\n") 456 | f.write("cmd /c \"%~dp0\\share\\qtcreator\\drivers\\openmv\\openmv.cmd\"\r\n") 457 | f.write("cmd /c \"%~dp0\\share\\qtcreator\\drivers\\arduino\\arduino.cmd\"\r\n") 458 | f.write("cmd /c \"%~dp0\\share\\qtcreator\\drivers\\dfuse.cmd\"\r\n") 459 | f.write("cmd /c \"%~dp0\\share\\qtcreator\\drivers\\vcr.cmd\"\r\n") 460 | f.write("ECHO All drivers have been successfully installed! & ECHO. & PAUSE & EXIT /D\r\n") 461 | output_dir = os.path.join(builddir, "openmv-ide") 462 | if os.path.exists(output_dir): 463 | shutil.rmtree(output_dir) 464 | shutil.copytree(os.path.join(builddir, "install"), output_dir) 465 | if os.system("cd " + output_dir + 466 | " && archivegen -f zip -c 9 ../" + installer_name + " bin lib share README.txt setup.cmd"): 467 | sys.exit("Make Failed...") 468 | 469 | elif sys.platform.startswith('darwin'): 470 | installer_name = "openmv-ide-mac-" + ideversion + ".dmg" 471 | if args.factory: installer_name = installer_name.replace("openmv", "openmv-factory") 472 | if not args.no_build_application: 473 | if os.system("cd " + builddir + 474 | " && cmake ../qt-creator" + 475 | " \"-DCMAKE_GENERATOR:STRING=Ninja\"" + 476 | " \"-DCMAKE_BUILD_TYPE:STRING=Release\"" + 477 | " \"-DCMAKE_PREFIX_PATH:PATH=" + qtdir + "\"" + 478 | " \"-DCMAKE_CXX_FLAGS_INIT:STRING=" + cxx_flags_init + "\"" + 479 | " && cmake --build . --target all" + 480 | " && cmake --install . --prefix . --component Dependencies" + 481 | " && rm -rf share" # Save disk space 482 | " && rm -rf src"): # Save disk space 483 | sys.exit("Make Failed...") 484 | if not args.no_sign_application: 485 | if os.system("cd " + builddir + 486 | " && python3 -u ../qt-creator/scripts/sign.py \"OpenMV IDE.app\" || true" + 487 | " && codesign --deep -s Application --force --options=runtime --timestamp \"OpenMV IDE.app\" || true" + 488 | " && ditto -c -k -rsrc --sequesterRsrc --keepParent OpenMV\\ IDE.app OpenMV\\ IDE.zip" + 489 | " && xcrun notarytool submit OpenMV\\ IDE.zip --keychain-profile \"AC_PASSWORD\" --wait || true" + 490 | " && xcrun stapler staple OpenMV\\ IDE.app || true" + 491 | " && rm \"OpenMV IDE.zip\" || true"): 492 | sys.exit("Make Failed...") 493 | if not args.no_build_installer: 494 | if os.system("cd " + builddir + 495 | " && ../qt-creator/scripts/makedmg.sh OpenMV\\ IDE.app " + installer_name): 496 | sys.exit("Make Failed...") 497 | if not args.no_sign_installer: 498 | if os.system("cd " + builddir + 499 | " && xcrun notarytool submit " + installer_name + " --keychain-profile \"AC_PASSWORD\" --wait || true" + 500 | " && xcrun stapler staple " + installer_name + " || true"): 501 | sys.exit("Make Failed...") 502 | 503 | elif sys.platform.startswith('linux'): 504 | installer_name = "openmv-ide-linux-x86_64-" + ideversion 505 | if args.factory: installer_name = installer_name.replace("openmv", "openmv-factory") 506 | installer_archive_name = installer_name + "-installer-archive.7z" 507 | if not args.no_build_application: 508 | if os.system("cd " + builddir + 509 | " && cmake ../qt-creator" + 510 | " -Wno-dev" + 511 | " \"-DCMAKE_GENERATOR:STRING=Ninja\"" + 512 | " \"-DCMAKE_BUILD_TYPE:STRING=Release\"" + 513 | " \"-DCMAKE_PREFIX_PATH:PATH=" + qtdir + "\"" + 514 | " \"-DCMAKE_CXX_FLAGS_INIT:STRING=" + cxx_flags_init + "\"" + 515 | " && cmake --build . --target all" + 516 | " && cmake --install . --prefix install" + 517 | " && cmake --install . --prefix install --component Dependencies" + 518 | " && mv share/qtcreator/arm install/share/qtcreator/arm" + 519 | " && mv share/qtcreator/stedgeai install/share/qtcreator/stedgeai" + 520 | " && rm -rf bin" + # Save disk space 521 | " && rm -rf lib" + # Save disk space 522 | " && rm -rf share" + # Save disk space 523 | " && rm -rf src"): # Save disk space 524 | sys.exit("Make Failed...") 525 | if not args.no_build_installer: 526 | if os.system("cd " + builddir + 527 | " && cd install" 528 | " && archivegen ../" + installer_archive_name + " bin lib share" + 529 | " && cd .." 530 | " && python3 -u ../qt-creator/scripts/packageIfw.py -i " + ifdir + 531 | " -v " + ideversion + " -a " + installer_archive_name + 532 | " " + installer_name): 533 | sys.exit("Make Failed...") 534 | else: 535 | with open(os.path.join(installdir, "README.txt"), 'w') as f: 536 | f.write("Please run setup.sh to install OpenMV IDE dependencies:\n\n") 537 | f.write(" ./setup.sh\n\n") 538 | f.write("And then run OpenMV IDE:\n\n") 539 | f.write(" ./bin/openmvide\n") 540 | with open(os.path.join(installdir, "setup.sh"), 'w') as f: 541 | f.write("#! /bin/sh\n\n") 542 | f.write("DIR=\"$(dirname \"$(readlink -f \"$0\")\")\"\n\n") 543 | f.write("sudo apt-get install -y libfontconfig1 libfreetype6 libxcb1 libxcb-glx0 libxcb-keysyms1 libxcb-image0 libxcb-shm0 libxcb-icccm4 libxcb-xfixes0 libxcb-shape0 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 build-essential\n") 544 | f.write("sudo apt-get install -y libpng16-16 libusb-1.0 python3 python3-pip python3-usb\n") 545 | f.write("sudo cp $DIR/share/qtcreator/pydfu/*.rules /etc/udev/rules.d/\n") 546 | f.write("sudo udevadm trigger\n") 547 | f.write("sudo udevadm control --reload-rules\n\n") 548 | f.write("cp -r \"$DIR/share/icons\" \"/home/$USER/.local/share/icons\"\n") 549 | f.write("sudo cp -r \"$DIR/share/icons\" /usr/share/\n") 550 | f.write("rm -rf \"$DIR/share/icons\"\n") 551 | f.write("sudo gtk-update-icon-cache\n\n") 552 | f.write("cat > \"/home/$USER/Desktop/openmvide.desktop\" << EOM\n") 553 | f.write("[Desktop Entry]\n") 554 | f.write("Type=Application\n") 555 | f.write("Name=OpenMV IDE\n") 556 | f.write("GenericName=OpenMV IDE\n") 557 | f.write("Comment=The IDE of choice for OpenMV Cam Development.\n") 558 | f.write("Exec=\"$DIR/bin/openmvide\" %F\n") 559 | f.write("Icon=OpenMV-openmvide\n") 560 | f.write("Terminal=false\n") 561 | f.write("Categories=Development;IDE;Electronics;OpenMV;\n") 562 | f.write("MimeType=text/x-python;\n") 563 | f.write("Keywords=embedded electronics;electronics;microcontroller;micropython;computer vision;machine vision;\n") 564 | f.write("StartupWMClass=openmvide\n") 565 | f.write("EOM\n") 566 | f.write("cp \"/home/$USER/Desktop/openmvide.desktop\" \"/home/$USER/.local/share/applications/\"\n") 567 | f.write("sudo cp \"/home/$USER/Desktop/openmvide.desktop\" /usr/share/applications/\n") 568 | os.chmod(os.path.join(installdir, "setup.sh"), 569 | os.stat(os.path.join(installdir, "setup.sh")).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 570 | if os.system("cd " + builddir + 571 | " && rm -rf openmv-ide" 572 | " && mv install openmv-ide" 573 | " && tar -czvf " + installer_name + ".tar.gz openmv-ide"): 574 | sys.exit("Make Failed...") 575 | 576 | else: 577 | sys.exit("Unknown Platform") 578 | 579 | if __name__ == "__main__": 580 | make() 581 | --------------------------------------------------------------------------------