diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d9416a2..bcf66bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,4 +110,4 @@ jobs: - name: Run headless test working-directory: ./tests - run: xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator playdate_tests.pdx + run: xvfb-run ../PlaydateSDK-*/bin/PlaydateSimulator playdate.pdx diff --git a/README.md b/README.md index 206ac85..d424ce7 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,12 @@ This package is an independent bindings library, not affiliated with Panic. You can quickly start using the bindings opening the `playdate_example` project included in this repository.
If you want to start from scratch, here are the steps to follow: -1. If you haven't run it already, start by initializing your nimble package and follow the instructions: +1. If you haven't done it already, start creating a folder (snake_case) and initializing your nimble package inside it running: ``` nimble init ``` +Choose `binary` as the package type. 2. Install the `playdate` package: @@ -57,8 +58,7 @@ nimble init nimble install playdate ``` -3. Move into your package directory.
-Add the `playdate` package as a dependency and configure the build tasks by running the following: +3. Add the `playdate` package as a dependency and configure the build tasks by running the following: ``` echo 'requires "playdate"' >> *.nimble; @@ -111,6 +111,11 @@ For simulator + device (pdx): nimble all ``` +You can also build for simulator and launch it in one command: +```sh +nimble simulate +``` + The example project `playdate_example` also contains VSCode launch configurations to build, start and debug your Nim application from the editor. Each project also contains a simple CMakeLists.txt as a starting point in case you'd want to add libraries or other external code. diff --git a/playdate.nimble b/playdate.nimble index 2a0e790..1a34866 100644 --- a/playdate.nimble +++ b/playdate.nimble @@ -1,6 +1,6 @@ # Package -version = "0.9.0" +version = "0.9.3" author = "Samuele Zolfanelli" description = "Playdate Nim bindings with extra features." license = "MIT" diff --git a/playdate_example/.vscode/launch.json b/playdate_example/.vscode/launch.json index 3005e63..a248804 100644 --- a/playdate_example/.vscode/launch.json +++ b/playdate_example/.vscode/launch.json @@ -10,7 +10,7 @@ "name": "Debug PDX", "program": "${env:PLAYDATE_SDK_PATH}/bin/Playdate Simulator", "args": [ - "${workspaceFolder}/playdate_example.pdx" + "${workspaceFolder}/playdate.pdx" ], "cwd": "${workspaceFolder}", "osx": { @@ -33,7 +33,7 @@ "program": "${env:PLAYDATE_SDK_PATH}/bin/Playdate Simulator", "preLaunchTask": "Build Universal PDX", "args": [ - "${workspaceFolder}/playdate_example.pdx" + "${workspaceFolder}/playdate.pdx" ], "cwd": "${workspaceFolder}", "osx": { @@ -56,7 +56,7 @@ "program": "${env:PLAYDATE_SDK_PATH}/bin/Playdate Simulator", "preLaunchTask": "Build Simulator PDX", "args": [ - "${workspaceFolder}/playdate_example.pdx" + "${workspaceFolder}/playdate.pdx" ], "cwd": "${workspaceFolder}", "osx": { diff --git a/playdate_example/CMakeLists.txt b/playdate_example/CMakeLists.txt index 40765e6..d41bc8e 100644 --- a/playdate_example/CMakeLists.txt +++ b/playdate_example/CMakeLists.txt @@ -5,6 +5,7 @@ # $ENV{PLAYDATE_PROJECT_NAME}: the project name # $ENV{PLAYDATE_MODULE_DIR}: the path to the installed playdate Nim module # $ENV{NIM_CACHE_DIR}: the path to the project Nim cache files +# $ENV{NIM_C_SOURCE_FILES}: list of semicolon-separated, Nim-generated C files that have to be compiled # $ENV{NIM_INCLUDE_DIR}: the path to required Nim header files cmake_minimum_required(VERSION 3.14) @@ -15,4 +16,8 @@ set(CMAKE_C_STANDARD 11) project($ENV{PLAYDATE_PROJECT_NAME} C ASM) # Include the playdate module CMake configuration -include($ENV{PLAYDATE_MODULE_DIR}/playdate.cmake) \ No newline at end of file +include($ENV{PLAYDATE_MODULE_DIR}/playdate.cmake) + +# Targets: +# ${PLAYDATE_GAME_NAME}: simulator +# ${PLAYDATE_GAME_DEVICE}: device \ No newline at end of file diff --git a/playdate_example/Source/audio/finally_see_the_light.wav b/playdate_example/source/audio/finally_see_the_light.wav similarity index 100% rename from playdate_example/Source/audio/finally_see_the_light.wav rename to playdate_example/source/audio/finally_see_the_light.wav diff --git a/playdate_example/Source/audio/jingle.wav b/playdate_example/source/audio/jingle.wav similarity index 100% rename from playdate_example/Source/audio/jingle.wav rename to playdate_example/source/audio/jingle.wav diff --git a/playdate_example/Source/images/nim_logo.png b/playdate_example/source/images/nim_logo.png similarity index 100% rename from playdate_example/Source/images/nim_logo.png rename to playdate_example/source/images/nim_logo.png diff --git a/playdate_example/Source/images/playdate_nim.png b/playdate_example/source/images/playdate_nim.png similarity index 100% rename from playdate_example/Source/images/playdate_nim.png rename to playdate_example/source/images/playdate_nim.png diff --git a/playdate_example/Source/json/data.json b/playdate_example/source/json/data.json similarity index 100% rename from playdate_example/Source/json/data.json rename to playdate_example/source/json/data.json diff --git a/playdate_example/Source/json/error.json b/playdate_example/source/json/error.json similarity index 100% rename from playdate_example/Source/json/error.json rename to playdate_example/source/json/error.json diff --git a/playdate_example/Source/pdxinfo b/playdate_example/source/pdxinfo similarity index 100% rename from playdate_example/Source/pdxinfo rename to playdate_example/source/pdxinfo diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 40765e6..9a466cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ # $ENV{PLAYDATE_PROJECT_NAME}: the project name # $ENV{PLAYDATE_MODULE_DIR}: the path to the installed playdate Nim module # $ENV{NIM_CACHE_DIR}: the path to the project Nim cache files +# $ENV{NIM_C_SOURCE_FILES}: list of semicolon-separated, Nim-generated C files that have to be compiled # $ENV{NIM_INCLUDE_DIR}: the path to required Nim header files cmake_minimum_required(VERSION 3.14) @@ -14,5 +15,9 @@ set(CMAKE_C_STANDARD 11) # Setup the project and its name from the environment project($ENV{PLAYDATE_PROJECT_NAME} C ASM) -# Include the playdate module CMake configuration -include($ENV{PLAYDATE_MODULE_DIR}/playdate.cmake) \ No newline at end of file +# Include the playdate module CMake configuration, this defines the targets +include($ENV{PLAYDATE_MODULE_DIR}/playdate.cmake) + +# Targets: +# ${PLAYDATE_GAME_NAME}: simulator +# ${PLAYDATE_GAME_DEVICE}: device \ No newline at end of file diff --git a/src/playdate.cmake b/src/playdate.cmake index d561ca2..100fe96 100644 --- a/src/playdate.cmake +++ b/src/playdate.cmake @@ -24,20 +24,18 @@ endif() set(CMAKE_CONFIGURATION_TYPES "Debug;Release") set(CMAKE_XCODE_GENERATE_SCHEME TRUE) -file(GLOB nim_source_files "$ENV{NIM_CACHE_DIR}/*.c") - # Game Name Customization -set(PLAYDATE_GAME_NAME $ENV{PLAYDATE_PROJECT_NAME}) -set(PLAYDATE_GAME_DEVICE $ENV{PLAYDATE_PROJECT_NAME}) +set(PLAYDATE_GAME_NAME $ENV{PLAYDATE_PROJECT_NAME}_simulator) +set(PLAYDATE_GAME_DEVICE $ENV{PLAYDATE_PROJECT_NAME}_device) # Include Nim required headers include_directories($ENV{NIM_INCLUDE_DIR}) if (TOOLCHAIN STREQUAL "armgcc") - add_executable(${PLAYDATE_GAME_DEVICE} ${nim_source_files}) + add_executable(${PLAYDATE_GAME_DEVICE} $ENV{NIM_C_SOURCE_FILES}) target_link_libraries(${PLAYDATE_GAME_DEVICE} rdimon c m gcc nosys) else() - add_library(${PLAYDATE_GAME_NAME} SHARED ${nim_source_files}) + add_library(${PLAYDATE_GAME_NAME} SHARED $ENV{NIM_C_SOURCE_FILES}) endif() include(${SDK}/C_API/buildsupport/playdate.cmake) @@ -51,67 +49,55 @@ if (TOOLCHAIN STREQUAL "armgcc") TARGET ${PLAYDATE_GAME_DEVICE} POST_BUILD COMMAND ${CMAKE_STRIP} --strip-unneeded -R .comment -g ${PLAYDATE_GAME_DEVICE}.elf - -o ${CMAKE_CURRENT_SOURCE_DIR}/Source/pdex.elf + -o ${CMAKE_CURRENT_SOURCE_DIR}/source/pdex.elf ) add_custom_command( TARGET ${PLAYDATE_GAME_DEVICE} POST_BUILD - COMMAND ${PDC} Source ${PLAYDATE_GAME_NAME}.pdx + COMMAND ${PDC} source playdate.pdx WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) set_property( TARGET ${PLAYDATE_GAME_DEVICE} PROPERTY ADDITIONAL_CLEAN_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/${PLAYDATE_GAME_NAME}.pdx + ${CMAKE_CURRENT_SOURCE_DIR}/playdate.pdx ) else () - if (MSVC) # MSVC not supported message(FATAL_ERROR "MSVC is not supported! Use MinGW.") - + elseif(MINGW) target_compile_definitions(${PLAYDATE_GAME_NAME} PUBLIC _WINDLL=1) - add_custom_command( - TARGET ${PLAYDATE_GAME_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_BINARY_DIR}/lib${PLAYDATE_GAME_NAME}.dll - ${CMAKE_CURRENT_SOURCE_DIR}/Source/pdex.dll) + set(DYLIB_EXT "dll") elseif(APPLE) target_sources(${PLAYDATE_GAME_NAME} PRIVATE ${SDK}/C_API/buildsupport/setup.c) - if(${CMAKE_GENERATOR} MATCHES "Xcode" ) - set(BUILD_SUB_DIR $/) - set_property(TARGET ${PLAYDATE_GAME_NAME} PROPERTY XCODE_SCHEME_ARGUMENTS \"${CMAKE_CURRENT_SOURCE_DIR}/${PLAYDATE_GAME_NAME}.pdx\") - set_property(TARGET ${PLAYDATE_GAME_NAME} PROPERTY XCODE_SCHEME_EXECUTABLE ${SDK}/bin/Playdate\ Simulator.app) - endif() - - add_custom_command( - TARGET ${PLAYDATE_GAME_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_BINARY_DIR}/${BUILD_SUB_DIR}lib${PLAYDATE_GAME_NAME}.dylib - ${CMAKE_CURRENT_SOURCE_DIR}/Source/pdex.dylib) + set(DYLIB_EXT "dylib") elseif(UNIX) target_sources(${PLAYDATE_GAME_NAME} PRIVATE ${SDK}/C_API/buildsupport/setup.c) - add_custom_command( - TARGET ${PLAYDATE_GAME_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_BINARY_DIR}/lib${PLAYDATE_GAME_NAME}.so - ${CMAKE_CURRENT_SOURCE_DIR}/Source/pdex.so) + set(DYLIB_EXT "so") + else() message(FATAL_ERROR "Platform not supported!") endif() + add_custom_command( + TARGET ${PLAYDATE_GAME_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_BINARY_DIR}/${BUILD_SUB_DIR}lib${PLAYDATE_GAME_NAME}.${DYLIB_EXT} + ${CMAKE_CURRENT_SOURCE_DIR}/source/pdex.${DYLIB_EXT}) + set_property( TARGET ${PLAYDATE_GAME_NAME} PROPERTY ADDITIONAL_CLEAN_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/${PLAYDATE_GAME_NAME}.pdx + ${CMAKE_CURRENT_SOURCE_DIR}/playdate.pdx ) add_custom_command( TARGET ${PLAYDATE_GAME_NAME} POST_BUILD - COMMAND ${PDC} ${CMAKE_CURRENT_SOURCE_DIR}/Source - ${CMAKE_CURRENT_SOURCE_DIR}/${PLAYDATE_GAME_NAME}.pdx) + COMMAND ${PDC} ${CMAKE_CURRENT_SOURCE_DIR}/source + ${CMAKE_CURRENT_SOURCE_DIR}/playdate.pdx) endif () diff --git a/src/playdate/build/config.nim b/src/playdate/build/config.nim index 0eb7086..3b6e5ea 100644 --- a/src/playdate/build/config.nim +++ b/src/playdate/build/config.nim @@ -37,6 +37,7 @@ when defined(simulator): switch("checks", "on") switch("index", "on") switch("debuginfo", "on") + switch("stackTrace", "on") switch("lineTrace", "on") switch("lineDir", "on") switch("debugger", "native") diff --git a/src/playdate/build/nimble.nim b/src/playdate/build/nimble.nim index d352b15..9e2787d 100644 --- a/src/playdate/build/nimble.nim +++ b/src/playdate/build/nimble.nim @@ -1,4 +1,4 @@ -import sequtils, strutils, os +import sequtils, strutils, os, json # This file is designed to be `included` directly from a nimble file, which will make `switch` and `task` # implicitly available. This block just fixes auto-complete in IDEs @@ -9,12 +9,16 @@ type Target = enum simulator = "simulator" device = "device" +type CompileInstructions = object + compile: seq[array[2, string]] + +type BuildFail = object of Defect + + proc nimble(args: varargs[string]) = ## Executes nimble with the given set of arguments exec @["nimble"].concat(args.toSeq).join(" ") -type BuildFail = object of Defect - proc playdatePath(): string = ## Returns the path of the playdate nim module var (paths, exitCode) = gorgeEx("nimble path playdate") @@ -30,7 +34,7 @@ proc playdatePath(): string = proc pdxName(): string = ## The name of the pdx file to generate - projectName() & ".pdx" + "playdate" & ".pdx" const SDK_ENV_VAR = "PLAYDATE_SDK_PATH" @@ -53,15 +57,34 @@ proc sdkPath*(): string = raise BuildFail.newException("SDK environment variable is not set: " & SDK_ENV_VAR) +proc simulatorPath(open: bool = false): string = + if defined(windows): + return sdkPath() / "bin" / "PlaydateSimulator.exe" + elif defined(macosx): + return (if open: "open " else: "") & sdkPath() / "bin" / "Playdate\\ Simulator.app" + else: + return sdkPath() / "bin" / "PlaydateSimulator" + +proc filesToCompile(target: Target): seq[string] = + let jsonString = readFile(nimcacheDir() / $target / projectName() & ".json") + let instructions = parseJson(jsonString).to(CompileInstructions) + + return instructions.compile.map( + proc(entry: array[2, string]): string = + return entry[0] + ) + proc build(target: Target) = ## Builds a target + let buildDir = "build" / $target + putEnv(SDK_ENV_VAR, sdkPath()) putEnv("PLAYDATE_MODULE_DIR", playdatePath()) putEnv("PLAYDATE_PROJECT_NAME", projectName()) putEnv("NIM_INCLUDE_DIR", getCurrentCompilerExe().parentDir.parentDir / "lib") + putEnv("NIM_C_SOURCE_FILES", filesToCompile(target).join(";").replace(DirSep, '/')) putEnv("NIM_CACHE_DIR", (nimcacheDir() / $target).replace(DirSep, '/')) - - let buildDir = "build" / $target + mkDir(buildDir) withDir(buildDir): case target: @@ -70,10 +93,9 @@ proc build(target: Target) = exec("cmake ../.. -DCMAKE_BUILD_TYPE=Debug" & " -G \"MinGW Makefiles\"") else: exec("cmake ../.. -DCMAKE_BUILD_TYPE=Debug" & " -G \"Unix Makefiles\"") - exec("make") of device: exec("cmake ../.. -DCMAKE_BUILD_TYPE=Release" & " -G \"Unix Makefiles\" --toolchain=" & (sdkPath() / "C_API" / "buildsupport" / "arm.cmake")) - exec("make") + exec("make") proc taskArgs(taskName: string): seq[string] = let args = command_line_params() @@ -85,46 +107,46 @@ task clean, "Clean the project folders": let args = taskArgs("clean") if args.contains("--simulator"): - rmDir(nimcacheDir() / "simulator") - rmDir("build" / "simulator") - rmFile("Source" / "pdex.dylib") - rmFile("Source" / "pdex.dll") - rmFile("Source" / "pdex.so") + rmDir(nimcacheDir() / $Target.simulator) + rmDir("build" / $Target.simulator) + rmFile("source" / "pdex.dylib") + rmFile("source" / "pdex.dll") + rmFile("source" / "pdex.so") elif args.contains("--device"): - rmDir(nimcacheDir() / "device") - rmDir("build" / "device") - rmFile("Source" / "pdex.bin") - rmFile("Source" / "pdex.elf") + rmDir(nimcacheDir() / $Target.device) + rmDir("build" / $Target.device) + rmFile("source" / "pdex.bin") + rmFile("source" / "pdex.elf") else: rmDir(nimcacheDir()) rmDir(pdxName()) rmDir("build") - rmFile("Source" / "pdex.bin") - rmFile("Source" / "pdex.dylib") - rmFile("Source" / "pdex.dll") - rmFile("Source" / "pdex.so") - rmFile("Source" / "pdex.elf") + rmFile("source" / "pdex.bin") + rmFile("source" / "pdex.dylib") + rmFile("source" / "pdex.dll") + rmFile("source" / "pdex.so") + rmFile("source" / "pdex.elf") task cdevice, "Generate C files for the device": nimble "-d:device", "build" -task csim, "Generate C files for the simulator": +task csimulator, "Generate C files for the simulator": nimble "-d:simulator", "build" task simulator, "Build for the simulator": - nimble "-d:simulator", "build" + nimble "csimulator" build Target.simulator task simulate, "Build and run in the simulator": nimble "simulator" - exec( (sdkPath() / "bin" / "PlaydateSimulator") & " " & pdxName()) + exec (simulatorPath(open = true) & " " & pdxName()) task device, "Build for the device": - nimble "-d:device", "build" + nimble "cdevice" build Target.device task all, "Build for both the simulator and the device": - nimble "csim" + nimble "csimulator" build Target.simulator nimble "cdevice" build Target.device @@ -138,10 +160,10 @@ task setup, "Initialize the build structure": if not fileExists("CMakeLists.txt"): cpFile(playdatePath() / "CMakeLists.txt", "CMakeLists.txt") - if not dirExists("Source"): - mkDir "Source" + if not dirExists("source"): + mkDir "source" - if not fileExists("Source/pdxinfo"): + if not fileExists("source/pdxinfo"): let cartridgeName = projectName() .replace("_", " ") .split(" ") @@ -158,7 +180,7 @@ task setup, "Initialize the build structure": .replace("-", "") .replace("_", "") writeFile( - "Source/pdxinfo", + "source/pdxinfo", [ "name=" & cartridgeName, "author=" & author, @@ -170,5 +192,5 @@ task setup, "Initialize the build structure": if not fileExists( ".gitignore"): ".gitignore".writeFile([ pdxName(), - "Source/pdex.*" + "source/pdex.*" ].join("\n")) diff --git a/tests/Source/main.lua b/tests/source/main.lua similarity index 100% rename from tests/Source/main.lua rename to tests/source/main.lua diff --git a/tests/Source/pdxinfo b/tests/source/pdxinfo similarity index 100% rename from tests/Source/pdxinfo rename to tests/source/pdxinfo