Tutorial  Updated

Switch Homebrew development

Switch Homebrew development


I've seen quite a lot questions about how to get into Homebrew development for the switch recently so I decided to share some information I would have found useful when I started.
This Guide is made on Windows 10. Refer to other resources for the installation process on other operating systems. After the setup is done, pretty much everything will be the same.

First of all, here's all the topics I'm going to cover in this Guide:
  • What do I need?
  • Setup and Installation
  • Tools
  • Examples and explanation
  • FAQ
If you find any errors, feel free to report them! So let's get started.



What do I need?Setup and InstallationToolsExamples and explanations


  1. First of all you'll need a Nintendo Switch with a way to get into RCM and some way to start up the custom loader (Hekate for example). There are many tutorials out there on how use those.

    Next, you'll need the following tools:
    • devkitPro : Make sure devkitA64 is selected during installation.
    • hb-menu : You need one of the latest commits to properly use nx-link later so you need to compile it from sources for now.
    • Atom : A nice and advanced text editor. You can use any other text editor you want but I recommend this one.
    • Cmder : An advanced console emulator for Windows. You can use the default Windows cmd but I recommend to switch to better one.
    • (Git : Version control tool. I recommend using it to share your progress and to open source your project so the community can benefit from it. It's not necessary though)
    • ASM/C/C++ knowledge : I'll try to explain everything as easy as possible but don't try getting into homebrew without any prior C programming experience.
    • A lot of patience : We don't have GDB yet so your only way to debug right now is via printf.

    Once you're sure you've got everything above you may continue to the next chapter.

  2. After you've installed devkitPro, Atom Cmder and hopefully git AND you're running the latest version of the hb-menu we can start with the setup process.
    First of all we need to correct the devkitPro environment variables. By default they get set to the paths used on Linux which won't work on Windows.
    To change them, press Win + Pause/Break and click on Advanced system settings in the window that pops up. Now you press on the Environment Variables... button.
    Now search in the System variables list for DEVKITARM, DEVKITPPC and DEVKITPRO. Change them to your devkitPro path. Now if it's not already there, add a DEVKITA64 variable and set the path to the devkitA64 folder path.
    After you're finished, it should look something like this:

    0uJYvpt.png

    Now find the PATH variable and add the path to the ../devkitPro/tools/bin directory to it.

    After this step you're basically done. You don't need any setup for Atom or Cmder. They just work out of the box.​

  3. For compilation and deployment we're going to use two things: make and nxlink. Both get installed by default together with devkitPro.

    If you use the attached template project, all you'll need to do is to type make. This will take care of the whole compilation part. To deploy your compiled project to the Switch now we use nxlink.

    First, enter the hbmenu on your Switch and press the Y Button. This brings you into the nxlink mode. The list of homebrews should disappear now. Now you can run the following command:

    nxlink -s -a 192.168.xxx.xxx out\<homebrew_name>.nro

    This nxlink command some arguments.
    • -s stands for server. It's used for debugging. With this option enabled, printf output can get redirected to our console.
    • -a stands for address. It's the IP address of the Switch. You can look it up either in your router settings or in the Switch settings.
    • out\<homebrew_name>.nro is the path to your homebrew executable. By default it gets built inside the /out folder.


  4. First of all, download the attached sample homebrew and load it up in Atom.
    There are a lot of great examples for many different things inside the /devkitPro/examples/switch folder. Read through those first if you want to start developing. You can also look at the source code of EdiZon, Checkpoint, the hbmenu or any other homebrew to find out how they did certain stuff. We're all a community and learn from each others :). For any other questions consult the official documentation of libnx. You may ask here in this thread as well but I can't promise to be able to help everybody.

    So, let's get started with the examples. More examples will come over time.

    Button detection & console outputGraphics output


    1. Code:
      #include <switch.h>
      #include <stdio.h>
      
      int main(int argc, char** argv) {
          u32 kdown = 0x00000000;
          u32 kdownOld = 0x00000000;
      
          gfxInitDefault();
          consoleInit(nullptr); //Init the console
      
          while(appletMainLoop()) {
              hidScanInput();    //Scan for input       
              kdown = hidKeysDown(CONTROLLER_P1_AUTO); //Read the currently pressed buttons and store that value into kdown
      
               //Edge detection. We don't want to print "Hello World" while A is pressed. We only want to print it once and then again on the next press
              if(kdown > kdownOld) {
                  if(kdown & KEY_A)
                      printf("Hello World\n"); //Prints to the console on screen
              }
      
              kdownOld = kdown;
               
              gfxFlushBuffers();   //Finish this frame
              gfxSwapBuffers();    //Display it on the screen
              gfxWaitForVsync();   //Wait till the last frame finished displaying before updating to avoid flickering
          }
          gfxExit();
          return 0;
      }

    2. Code:
      #include <switch.h>
      
      int main(int argc, char** argv) {
         u8 *framebuffer;
         u32 framebuffer_width;
         u32 framebuffer_height;
      
         gfxInitDefault();
         framebuffer = gfxGetFramebuffer(&framebuffer_width, &framebuffer_height);  //Gets the address of the framebuffer so we can draw to it
      
         while(appletMainLoop()) {
             //The framebuffer is layed out in RGBA8 format. We're coloring it entirely in Magenta (0xFF00FFFF)
              for(u16 x = 0; x < framebuffer_width; x++) {
                  for(u16 y = 0; y < framebuffer_height; y++) {
                       framebuffer[(x + y * framebuffer_width) * 4 + 0] = 0xFF;   //Red
                       framebuffer[(x + y * framebuffer_width) * 4 + 1] = 0x00;   //Green
                       framebuffer[(x + y * framebuffer_width) * 4 + 2] = 0xFF;   //Blue
                       framebuffer[(x + y * framebuffer_width) * 4 + 3] = 0xFF;   //Alpha
                  }
              }
            
              gfxFlushBuffers();   //Finish this frame
              gfxSwapBuffers();    //Display it on the screen
              gfxWaitForVsync();   //Wait till the last frame finished displaying before updating to avoid flickering
          }
      
          gfxExit();
      
         return 0;
      }
 

Attachments

Last edited by WerWolv,
Anyone got a basic hello world handy to see? Just to see how to write on the screen

And what's the basics if you're trying to port an open source game?
 
Anyone got a basic hello world handy to see? Just to see how to write on the screen

And what's the basics if you're trying to port an open source game?

If you need to setup the environment too, check out my tutorial with Visual studio. If not, this tutorial shows you a simple hello world. The basis are coding knowledge and devkitpro setup.
 
My experience so far is writing hello world (which I couldn't see, it would just exit straight away) and then making it loop which I assumed worked because it stayed on the black screen lol

Just linking to other files is what I need to tackle next
 
My experience so far is writing hello world (which I couldn't see, it would just exit straight away) and then making it loop which I assumed worked because it stayed on the black screen lol

Just linking to other files is what I need to tackle next
Then you did not follow the steps because this tutorial shows a hello world by console print xF btw, check my setup tutorial after retrying this one again :)
 
This is cool! I was just learning about SDL some time ago. I only have focused on C++ so I hope that is enough lol (I know C++ can do stuff from C) can't wait to make things on Switch.
 
When trying to compile the example, i get those errors, and i don't understant why. Are these functions dependent on something else than libnx ?

D:\Documents\Prog\Switch\Dev>make
main.cpp
aarch64-none-elf-g++ -MMD -MP -MF /d/Documents/Prog/Switch/Dev/build/main.d -g -Wall -O3 -ffunction-sections -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -DVERSION_MAJOR=1 -DVERSION_MINOR=0 -DVERSION_MICRO=0 -I/d/Documents/Prog/Switch/Dev/include -I/D\devkitPro/portlibs/switch/include -ID:\devkitPro/libnx/include -I/d/Documents/Prog/Switch/Dev/build -D__SWITCH__ -fno-rtti -fno-exceptions -std=gnu++17 -c /d/Documents/Prog/Switch/Dev/source/main.cpp -o main.o
D:/Documents/Prog/Switch/Dev/source/main.cpp: In function 'int main(int, char**)':
D:/Documents/Prog/Switch/Dev/source/main.cpp:10:3: error: 'gfxInitDefault' was not declared in this scope
gfxInitDefault();
^~~~~~~~~~~~~~
D:/Documents/Prog/Switch/Dev/source/main.cpp:26:3: error: 'gfxExit' was not declared in this scope
gfxExit();
^~~~~~~
D:/Documents/Prog/Switch/Dev/source/main.cpp:26:3: note: suggested alternative: 'fsExit'
gfxExit();
^~~~~~~
fsExit
make[1]: *** [D:\devkitPro/devkitA64/base_rules:14: main.o] Error 1
make: *** [Makefile:160: build] Error 2
 
When trying to compile the example, i get those errors, and i don't understant why. Are these functions dependent on something else than libnx ?

D:\Documents\Prog\Switch\Dev>make
main.cpp
aarch64-none-elf-g++ -MMD -MP -MF /d/Documents/Prog/Switch/Dev/build/main.d -g -Wall -O3 -ffunction-sections -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -DVERSION_MAJOR=1 -DVERSION_MINOR=0 -DVERSION_MICRO=0 -I/d/Documents/Prog/Switch/Dev/include -I/D\devkitPro/portlibs/switch/include -ID:\devkitPro/libnx/include -I/d/Documents/Prog/Switch/Dev/build -D__SWITCH__ -fno-rtti -fno-exceptions -std=gnu++17 -c /d/Documents/Prog/Switch/Dev/source/main.cpp -o main.o
D:/Documents/Prog/Switch/Dev/source/main.cpp: In function 'int main(int, char**)':
D:/Documents/Prog/Switch/Dev/source/main.cpp:10:3: error: 'gfxInitDefault' was not declared in this scope
gfxInitDefault();
^~~~~~~~~~~~~~
D:/Documents/Prog/Switch/Dev/source/main.cpp:26:3: error: 'gfxExit' was not declared in this scope
gfxExit();
^~~~~~~
D:/Documents/Prog/Switch/Dev/source/main.cpp:26:3: note: suggested alternative: 'fsExit'
gfxExit();
^~~~~~~
fsExit
make[1]: *** [D:\devkitPro/devkitA64/base_rules:14: main.o] Error 1
make: *** [Makefile:160: build] Error 2

the gfx functions that are erroring were present in a previous version of libnx, and were removed in 1.5 if i remember correctly
 
  • Like
Reactions: LawnMeower
I'm having problems setting up devkitPro on Windows 10 and at the point where the devkitPro environment variables need to be corrected I can't get any further. DEVKITARM and DEVKITPPC are included in my list of system variables, but none of these folders are in my devkitPro folder. Also, I could not make a devkitA64 selection when installing devkitpro as described in the manual. I could only select the components. I only selected Switch Development there. Does anyone have a clue what I did wrong? Thanks in advance.
 
Last edited by Muxi,
Getting this error:

[...]/main.cpp:11:3: error: 'gfxInitDefault' was not declared in this scope
11 | gfxInitDefault();
| ^~~~~~~~~~~~~~
[...]/main.cpp:27:3: error: 'gfxExit' was not declared in this scope; did you mean 'nfcExit'?
27 | gfxExit();
| ^~~~~~~

What is causing this? Am I missing something?
 
Getting this error:

[...]/main.cpp:11:3: error: 'gfxInitDefault' was not declared in this scope
11 | gfxInitDefault();
| ^~~~~~~~~~~~~~
[...]/main.cpp:27:3: error: 'gfxExit' was not declared in this scope; did you mean 'nfcExit'?
27 | gfxExit();
| ^~~~~~~

What is causing this? Am I missing something?
stupid question but do you have latest devkitpro installed with switch dependencies?
 
stupid question but do you have latest devkitpro installed with switch dependencies?
Yes, I installed everything that the guide said other than atom and cmder
I also set up the environment variables as said.

Edit 1:

the gfx functions that are erroring were present in a previous version of libnx, and were removed in 1.5 if i remember correctly
Ah. That's probably what the problem is

Edit 2:

Fixed it by just commenting out those lines

Edit 3:

The build works, but nothing is actually displayed to the screen, so I guess that didn't really help anything
 
Last edited by Daniel_Bradbury,
Sorry for necro, but I'm constantly getting this error every time I run make on any tesla overlay. I could really use some help.


Error after running make on QuickNTP:
Code:
In file included from C:\devkitPro/libnx/include/switch.h:79,
                 from C:/Users/user/Downloads/QuickNTP-1.2.0/QuickNTP-1.2.0/libs/libtesla/include/tesla.hpp:22,
                 from C:/Users/user/Downloads/QuickNTP-1.2.0/QuickNTP-1.2.0/source/main.cpp:2:
C:\devkitPro/libnx/include/switch/services/hid.h:1756:17: note: declared here
 1756 | void DEPRECATED hidTouchRead(touchPosition *pos, u32 point_id); ///< \deprecated
      |                 ^~~~~~~~~~~~
make[1]: *** [C:\devkitPro/devkitA64/base_rules:14: main.o] Error 1
make: *** [Makefile:170: build] Error 2

Full console output: https://pastebin.com/vCt3Lj75


EDIT: I found what the problem was. tesla.hpp from libtesla has a syntax error at line 3468 and 3494, but I think it's above my skill level to fix it.

Code:
Code in question:             hidsysAcquireHomeButtonEventHandle(&shData->homeButtonPressEvent);

Error:
In file included from C:/Users/user/Documents/GitHub/NetTest-ovl/source/main.cpp:2:
C:/Users/user/Documents/GitHub/NetTest-ovl/libs/libtesla/include/tesla.hpp: In function 'void tsl::impl::homeButtonDetector(void*)':
C:/Users/user/Documents/GitHub/NetTest-ovl/libs/libtesla/include/tesla.hpp:3468:77: error: too few arguments to function 'Result hidsysAcquireHomeButtonEventHandle(Event*, bool)'
 3468 |             hidsysAcquireHomeButtonEventHandle(&shData->homeButtonPressEvent);
      |                                                                             ^

EDIT 2: Replaced the tesla.hpp in from the latest release with this one from GitHub, and it's compiling up to a point. Thankfully at this point it's only errors in my coding.
 
Last edited by vaugerbird,

Site & Scene News

Popular threads in this forum