diff --git a/SerialPrograms/BuildInstructions/Build-Ubuntu-Qt6.8.2.md b/SerialPrograms/BuildInstructions/Build-Ubuntu-Qt6.8.2.md index ad65c8191a..198091f76c 100644 --- a/SerialPrograms/BuildInstructions/Build-Ubuntu-Qt6.8.2.md +++ b/SerialPrograms/BuildInstructions/Build-Ubuntu-Qt6.8.2.md @@ -1,15 +1,16 @@ -# How to Build (Qt 6.8.2) - Ubuntu 24.04 +# How to Build (Qt 6.8.2) - Linux -Note that our Ubuntu setup does not work. The video display flickers to the point of being unusable. +Note that our Linux setup might not work. The video display can flicker to the point of being unusable. ## Build Tools: -Install the following packages: +Install the following build requirements, these steps will use ubuntu packages but the steps will be the same on your distro: ``` -sudo apt install cmake -sudo apt install libglx-dev libgl1-mesa-dev -sudo apt install libopencv-dev +git cmake ninja-build gcc g++ qt6-base-dev qt6-multimedia-dev qt6-serialport-dev libopencv-dev libonnx-dev libasound2-dev libsystemd-dev +dpkg # To build .deb packages for Debian based distros +rpm # To build .rpm packages for RHEL based distros +pacman-package-manager # To build .pkg packages for Arch based distros ``` @@ -30,20 +31,30 @@ sudo apt install libopencv-dev ![](Images/Windows-Install-Qt6.7.3-Custom.png) ![](Images/Windows-Install-Qt6.8.2-Components.png) +### Alternatively: +1. ```curl -L https://download.qt.io/official_releases/online_installers/qt-online-installer-linux-x64-online.run -o qt.run``` +2. ```chmod +x qt.run``` +3. ```./qt.run install qt6.8.2-full-dev``` +4. ```export CMAKE_PREFIX_PATH=/opt/Qt/6.8.2/gcc_64:$CMAKE_PREFIX_PATH``` + ## Setup: +### Package: 1. Clone this repo. -2. Clone the [Packages Repo](https://github.com/PokemonAutomation/Packages). -3. In the `Packages` repo, copy the `SerialPrograms/Resources` folder into the root of the `Arduino-Source` repo. - -![](Images/Directory.png) - -4. Open Qt Creator. -5. Click on `File` -> `Open File or Project`. -6. Navigate to `SerialPrograms` and select `CMakeLists.txt`. -7. Enable parallel build: Build & Run -> Build Steps -> Build -> Details -> CMake arguments: `-j16` (the # of cores you have) -8. At the bottom left corner, click on the little monitor and select `Release with Debug Information`. -9. Still in the bottom left corner, click the upper green arrow to compile and launch the program. +2. Open a terminal in the folder ```Arduino-Source/SerialPrograms/Scripts/Linux``` +3. Run the script ```./packages.sh (PACKAGE TYPE)``` + - PACKAGE TYPE: + - DEB - .deb package + - RPM - .rpm package + - PKG - .pkg package + - TGZ - Generic package +4. Find the package at ```/Arduino-Source/SerialPrograms/build``` +5. Install the package ```apt install ./pokemon-automation--x86_64.deb``` + +### Source: +1. Clone this repo. +2. Open a terminal in ```Arduino-Source/SerialPrograms``` +3. Compile the source code ```cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-O2 -march=native -Wno-odr" -DCMAKE_CXX_FLAGS="-O2 -march=native -Wno-odr" && ninja -C build```
diff --git a/SerialPrograms/CMakeLists.txt b/SerialPrograms/CMakeLists.txt index ec74150758..d0429851e8 100644 --- a/SerialPrograms/CMakeLists.txt +++ b/SerialPrograms/CMakeLists.txt @@ -713,3 +713,4 @@ endif() # Add command-line executable (GUI-free) from subdirectory include(Source/CommandLine/CommandLineExecutable.cmake) +include(cmake/CPack.cmake) \ No newline at end of file diff --git a/SerialPrograms/Scripts/Linux/PKGBUILD b/SerialPrograms/Scripts/Linux/PKGBUILD new file mode 100644 index 0000000000..c1d11569b5 --- /dev/null +++ b/SerialPrograms/Scripts/Linux/PKGBUILD @@ -0,0 +1,65 @@ +pkgname=pokemon-automation +pkgver=1 +pkgrel=1 +pkgdesc="Pokemon Automation Serial Programs" +arch=('x86_64') +url="https://github.com/PokemonAutomation/Arduino-Source" +license=('MIT') +options=('!debug') + +depends=('qt6-base' 'qt6-multimedia' 'qt6-serialport' 'qt6-imageformats' \ + 'qt6-multimedia-gstreamer' 'gstreamer' 'opencv' 'mesa' \ + 'libglvnd' 'hdf5' 'vtk' 'tesseract' 'onnxruntime') + +makedepends=('cmake' 'ninja') + +source=("Arduino-Source.tar.gz") +sha256sums=('SKIP') + +build() { + CCACHE_ARGS=() + if command -v ccache >/dev/null 2>&1; then + echo "[INFO] Using ccache for compilation" + CCACHE_ARGS=(-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache) + fi + + mkdir -p "$srcdir/Arduino-Source/SerialPrograms/build" + cd "$srcdir/Arduino-Source/SerialPrograms/build" + + cmake .. \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_FLAGS="-O2 -g0 -fno-record-gcc-switches -fno-ident -Wno-odr" \ + -DCMAKE_CXX_FLAGS="-O2 -g0 -fno-record-gcc-switches -fno-ident -Wno-odr" \ + "${CCACHE_ARGS[@]}" + + ninja -j$(( $(nproc) - 1)) +} + +package() { + install -Dm755 $srcdir/Arduino-Source/SerialPrograms/build/SerialPrograms \ + "$pkgdir/usr/bin/SerialPrograms" + + install -d "$pkgdir/usr/share/SerialPrograms" + cp -r "$srcdir/Arduino-Source/SerialPrograms/build/Resources/." \ + "$pkgdir/usr/share/SerialPrograms/Resources/" + cp -r "$srcdir/Arduino-Source/SerialPrograms/build/Firmware/." \ + "$pkgdir/usr/share/SerialPrograms/Firmware/" + + install -d "$pkgdir/usr/share/icons/hicolor/256x256/apps" + install -Dm644 $srcdir/Arduino-Source/IconResource/SerialPrograms.png \ + "$pkgdir/usr/share/icons/hicolor/256x256/apps/SerialPrograms.png" + + install -d "$pkgdir/usr/share/applications" + cat > "$pkgdir/usr/share/applications/SerialPrograms.desktop" </dev/null 2>&1; then + echo " [MISSING] $pkg requires $TOOL" + TARGETS=("${TARGETS[@]/$pkg}") + else + echo " [OK] $pkg -> $TOOL found" + fi + else + echo " [OK] $pkg -> no external tool required" + fi +done + + +# Check CCache +CCACHE_ARGS=() +if command -v ccache >/dev/null 2>&1; then + echo " [INFO] ccache found, caching compilation" + CCACHE_ARGS=(-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache) +fi + + +# Build CMake +cd "$SOURCE_DIR" +cmake "$SOURCE_DIR" -G Ninja -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_FLAGS="-O2 -g0 -fno-record-gcc-switches -fno-ident -Wno-odr" \ + -DCMAKE_CXX_FLAGS="-O2 -g0 -fno-record-gcc-switches -fno-ident -Wno-odr" \ + "${CCACHE_ARGS[@]}" + +cd "$SOURCE_DIR/build" +ninja -j$(( $(nproc) - 1)) + + +# Build Packages +cd "$BUILD_DIR" +for pkg in "${TARGETS[@]}"; do + case "$pkg" in + DEB|RPM|TGZ) + echo "Building $pkg package with CPack..." + cpack -G "$pkg" + ;; + PKG) + echo "Building PKG package with makepkg..." + cp "$SCRIPT_DIR/PKGBUILD" "." + git -C "$SOURCE_DIR/.." archive --format=tar.gz --prefix=Arduino-Source/ \ + HEAD > "Arduino-Source.tar.gz" + makepkg -Cf + ;; + *) + echo "Unknown package type: $pkg" + ;; + esac +done + +echo "Package creation complete." +echo "Packages can be found here: $BUILD_DIR" \ No newline at end of file diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp index 0305055e1e..1fec25fef8 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp @@ -118,7 +118,7 @@ GlobalSettings::GlobalSettings() false, "Stats File:
Use the stats file here. Multiple instances of the program can use the same file.", LockMode::LOCK_WHILE_RUNNING, -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__linux__) QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString() + "/UserSettings/PA-Stats.txt", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString() + "/UserSettings/PA-Stats.txt" #else @@ -133,6 +133,10 @@ GlobalSettings::GlobalSettings() #if defined(__APPLE__) QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString() + "/TempFiles/", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString() + "/TempFiles/" +#elif defined(__linux__) + // /tmp/ + QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(), + QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString() #else "TempFiles/", "TempFiles/" diff --git a/SerialPrograms/Source/CommonFramework/Globals.cpp b/SerialPrograms/Source/CommonFramework/Globals.cpp index 192a54f045..6d2d95b4de 100644 --- a/SerialPrograms/Source/CommonFramework/Globals.cpp +++ b/SerialPrograms/Source/CommonFramework/Globals.cpp @@ -114,6 +114,10 @@ const size_t LOG_HISTORY_LINES = 10000; namespace{ QString get_application_base_dir_path(){ +#if defined(__linux__) + // ~/.local/share/SerialPrograms + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); +#else QString application_dir_path = qApp->applicationDirPath(); if (application_dir_path.endsWith(".app/Contents/MacOS")){ // a macOS bundle. Change working directory to the folder that hosts the .app folder. @@ -122,8 +126,24 @@ QString get_application_base_dir_path(){ return base_folder_path; } return application_dir_path; +#endif } std::string get_resource_path(){ +#if defined(__linux__) + // Look for Resources installed as part of a package + QString system_path = "/usr/share/SerialPrograms/Resources/"; + if (QDir(system_path).exists()) { + return system_path.toStdString(); + } + // Check for Resources in the current working directory + QString cwd_path = "./Resources/"; + if (QDir(cwd_path).exists()) { + return cwd_path.toStdString(); + } + // Prevents a prompt telling the user to install Resources to /usr/Resources + // if the binary is located at /usr/bin/SerialPrograms + return (get_application_base_dir_path() + "/Resources/").toStdString(); +#else // Find the resource directory. QString path = get_application_base_dir_path(); for (size_t c = 0; c < 5; c++){ @@ -135,6 +155,7 @@ std::string get_resource_path(){ path += "/.."; } return (QCoreApplication::applicationDirPath() + "/../Resources/").toStdString(); +#endif } std::string get_training_path(){ // Find the training data directory. @@ -151,6 +172,10 @@ std::string get_training_path(){ } std::string get_runtime_base_path(){ +#if defined(__linux__) + // ~/.local/share/SerialPrograms/ + return (get_application_base_dir_path() + "/").toStdString(); +#else // On MacOS, find the writable application support directory if (QSysInfo::productType() == "macos" || QSysInfo::productType() == "osx"){ // QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) returns @@ -167,6 +192,7 @@ std::string get_runtime_base_path(){ return appSupportPath.toStdString() + "/"; } return "./"; +#endif } std::string get_setting_path(){ diff --git a/SerialPrograms/Source/CommonFramework/Main.cpp b/SerialPrograms/Source/CommonFramework/Main.cpp index 455b9a2f96..d231c2080d 100644 --- a/SerialPrograms/Source/CommonFramework/Main.cpp +++ b/SerialPrograms/Source/CommonFramework/Main.cpp @@ -39,6 +39,7 @@ #include "Windows/MainWindow.h" #include +#include using std::cout; using std::endl; @@ -48,6 +49,12 @@ using namespace PokemonAutomation; Q_DECLARE_METATYPE(std::string) void set_working_directory(){ +#if defined(__linux__) + // ~/.local/share/SerialPrograms + QString base_folder_path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + std::cout << base_folder_path.toStdString() << std::endl; + QDir::setCurrent(base_folder_path); +#else QString application_dir_path = qApp->applicationDirPath(); if (application_dir_path.endsWith(".app/Contents/MacOS")){ // a macOS bundle. Change working directory to the folder that hosts the .app folder. @@ -55,6 +62,7 @@ void set_working_directory(){ QString base_folder_path = QFileInfo(app_bundle_path).dir().absolutePath(); QDir::setCurrent(base_folder_path); } +#endif } diff --git a/SerialPrograms/cmake/CPack.cmake b/SerialPrograms/cmake/CPack.cmake new file mode 100644 index 0000000000..daa6063809 --- /dev/null +++ b/SerialPrograms/cmake/CPack.cmake @@ -0,0 +1,78 @@ +### Packaging +# Install binary +install( + TARGETS SerialPrograms + RUNTIME DESTINATION bin +) + +# Resources +install( + DIRECTORY ${CMAKE_BINARY_DIR}/Resources/ + DESTINATION share/SerialPrograms/Resources +) + +# Firmware +install( + DIRECTORY ${CMAKE_BINARY_DIR}/Firmware/ + DESTINATION share/SerialPrograms/Firmware +) + +# App icon +install( + FILES ${CMAKE_SOURCE_DIR}/../IconResource/SerialPrograms.png + DESTINATION share/icons/hicolor/256x256/apps +) + +# Desktop Entry +install( + FILES ${CMAKE_SOURCE_DIR}/../IconResource/SerialPrograms.desktop + DESTINATION share/applications +) + +# License +install( + FILES ${CMAKE_SOURCE_DIR}/../LICENSE + DESTINATION share/licenses/SerialPrograms +) + +# Discord Partner Library +install( + FILES ${CMAKE_SOURCE_DIR}/../3rdPartyBinaries/discord_social_sdk_linux/lib/release/libdiscord_partner_sdk.so + DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +# ONNX Runtime Library +install( + FILES ${CMAKE_BINARY_DIR}/onnxruntime-linux-x64-1.23.0/lib/libonnxruntime.so.1.23.0 + DESTINATION lib + RENAME libonnxruntime.so.1 + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) + +### CPack Config +set(CPACK_GENERATOR "DEB;RPM;TGZ") +set(CPACK_PACKAGE_NAME "pokemon-automation") +set(CPACK_PACKAGE_VERSION ${SerialPrograms_VERSION}) +set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}") + +# Debian +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "PokemonAutomation") +set(CPACK_DEBIAN_PACKAGE_DEPENDS + "libqt6core6, libqt6gui6, libqt6widgets6, libqt6multimedia6, libqt6serialport6, libqt6multimediawidgets6, \ + qt6-image-formats-plugins, gstreamer1.0-plugins-base, gstreamer1.0-plugins-good, gstreamer1.0-plugins-bad, \ + gstreamer1.0-plugins-ugly, libopencv-core410, libopencv-imgproc410, libglx0, libgl1, libhdf5-310, libvtk9.3, \ + tesseract-ocr" +) + +# RPM +set(CPACK_RPM_PACKAGE_LICENSE "MIT") +set(CPACK_RPM_PACKAGE_GROUP "Applications/Utilities") +set(CPACK_RPM_PACKAGE_REQUIRES + "qt6-qtbase, qt6-qtmultimedia, qt6-qtserialport, qt6-qtimageformats, gstreamer1, gstreamer1-plugins-base, \ + gstreamer1-plugins-good, gstreamer1-plugins-bad-free, gstreamer1-plugins-ugly, gstreamer-plugin-libav, \ + opencv, mesa-libGL, libglvnd, hdf5, vtk, tesseract, leptonica, onnxruntime" +) + +include(CPack) \ No newline at end of file