-
Notifications
You must be signed in to change notification settings - Fork 0
Developer Resources
In order to use this repository you will need:
- The QNX Software Development Platform
-
qcc(comes with above)
This guide assumes that you have already followed the Installing QNX Development Tools guide and have all of the QNX development tools on your system.
You should clone this repository using the --recursive flag in order to clone the repository and it's sub modules.
If you make any changes to a sub module, those changes will have to go through the pull request/merge process enforced for that sub module's repository.
Changes made on any of the files that are native to the qnx-stack repository will go through the pull request/merge process enforced here. See the contributing guidelines for what is enforced on this repository.
As described above, do all sub module specific work within the appropriate sub module directory. Changes will be handled by the sub module's repository. As you perform changes, you will notice that the main repository will list sub module changes like so:
[your-username][/path/to/qnx-stack]> git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: packager (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
[your-username][/path/to/qnx-stack]>
This is because you've updated the packager (or whatever sub module you were working on) module with new changes. Git pins sub modules at a specific commit in case the main project is not ready to upgrade a sub module version yet (for compatibility).
For our purposes, we don't care about pinning sub modules at a specific commit. Therefore, if you make a change to a
sub module and see a similar git status output as the above, you may commit the sub module changes under a commit that
reads "Updated submodule(s)". You can open that as a pull request right away.
Alternatively, you do not need to commit the sub module changes to the main repository at all. All developers will be
able to update their local copy of the sub modules using the git submodule update --recursive command. You can commit
the changes every time you modify the qnx-stack native files instead.
As mentioned previously, use git submodule update --recursive to update all sub modules. Because this is verbose, it
is baked into the project Makefile. Run make update instead.
All of the repositories enforce formatted code using clang-format. You can download the files to build clang-format from their GitHub here. If you use Visual Studio Code, you can also get clang-format through the C/C++ extension. The tool comes with a git integration in the form of git-clang-format, which allows you to only format staged changes.
Your workflow should be as follows:
- Modify the code however you please.
- Stage your changes by using
git add <files to stage> - Format your code using
git clang-format - Stage your changes again
- Commit your changes with a meaningful commit message
- Push your changes once you've committed everything you want to change
At this point, your pull request should pass all the formatting checks. If it doesn't, check the job status output and
see what wasn't formatted correctly. You can re-run clang-format using the steps above, or you can fix it by hand and
commit your changes (a commit message of "Fixed formatting." is fine in this case).
If this sounds like too much work, see Configuring Your Editor to see how you can format on save.
Your pull request will never fail a workflow due to documentation issues, but others may request you add documentation before getting approving reviews.
All documentation is automatically generated using Doxygen and then hosted on GitHub pages. This means you must write your documentation in a certain format. This format is called JavaDoc style. You can check out the guide on how to write in that format, or wing it by looking at how other documentation in the repositories has been written.
The key for Java-Doc is that comments must begin in a double star:
/** <--- Notice this double star
* Here you write whatever you want about your code.
* @param example Here you can write a description for parameters
*/There are many different @ tags in JavaDoc, but we will only use a subset.
In order to develop for QNX, you will need several tools. The main tool we use is QNX's C compiler, qcc. This tool
requires certain environment variables to be set in order to do its job. QNX includes scripts to set up this environment
with your installation.
QNX has not yet supported Powershell for its scripts, and I have been unable to replicate the scripts for Powershell
yet. You will need to use Windows' command shell (cmd.exe), or you can run the cmd command from your Powershell
instance to switch shells.
Once you're in the command shell, you will need to run the qnxsdp-env.bat file located in the \qnx710 installation
directory. The full path to that file might look something like C:/Users/<your username>/qnx710/qnxsdp-env.bat. Once
your type this path into your command shell and hit enter, you will see all the environment variables printed. Your QNX
environment is now set up, and you can use qcc.
You will also notice that you have access to common POSIX commands, like ls. You will also be using a QNX version of
make (instead of whatever version you have installed) which can run Makefiles as though they are executed in a bash
shell.
You will need to source the qnxsdp-env.sh script located in your /qnx710 directory. The full path to that file
should be ~/qnx710/qnxsdp-env.sh (assuming you selected the default install location). Once sourced, you should see
the environment variables printed out to your console. You can now use qcc.
Similarly to Linux, you need to source the qnxsdp-env.sh script in the ~/qnx710 directory. The full command is
source qnxsdp-env.sh, assuming that you selected the default install location.
However, since Mac defaults to zsh, when you try and run the above command you will likely get an error
such as This script can only be sourced from bash. This error does not detract from zsh being better than bash.
Enter the bash command in the terminal to switch to the Bash shell. The command prompt should look like
bash-#.#$
Now that you are in bash, enter the same source qnxsdp-env.sh command as above, and this time you should see all
the environment variables printed in the terminal. This operation isn't persistent, but if you want to make it
persistent, enter the following into your .bashrc file in your home directory:
source ~/qnx710/qnxsdp-env.sh
After that, it will source the file each time you open the bash shell. You will know it works if the environment
variables are displayed each time you launch bash, and if you can run the qcc command in the bash shell.
As stated above, the C/C++ extension that Microsoft offers includes clang-format and other useful features for development. After installing the extension pack you can set up clang-format to format your modifications when a file is saved, saving you time. Under Settings > Editor, check Format On Save then set the Format On Save Mode to "modifications", and under Settings > Extensions > C/C++, set Clang_format_style to "file" and Formatting to "clangFormat".
You can also configure a custom keyboard shortcut to make VSCode run the QNX environment variable script in your current terminal. Press ctrl+k then ctrl+s to open the keyboard shortcuts menu, then in the top right of the window click "Open Keyboard Shortcuts (JSON)". Add an entry to the list that looks like this, changing the key (keybinding) and text (what text you're entering in the terminal):
"key": "ctrl+k ctrl+t",
"command": "workbench.action.terminal.sendSequence",
"args": {
"text": "\"some_path\\qnx710\\qnxsdp-env.bat\"\n"
}
If you're interested in automatically generating the comments for Doxygen, you can install the Doxygen Documentation Generator and set extension's Generic: Breif Template to be empty. The extension will automatically create Doxygen comments when you type /** and press enter.
Using the C/C++ intellisense feature with qcc can cause some issues, so it might be easier for you to use clangd instead. Simply get the clangd extension (if you don't have the actual clangd excutable on your computer, it will offer to install it for you) and follow the instructions below for creating the compile_commands.json file.
If your editor has a Language Server Protocol (LSP) which requires a compile_commands.json file to provide proper
auto completion and linting (such as clangd), you should install the compiledb Python module.
Clangd in particular will throw errors using its default configuration. You will need to give it a new "query driver" and modify your compile commands by hand.
In your generated compile_commands.json file (see the subheading for your OS to generate these), you will need to add
two more arguments: -D__QNXNTO__ and -D__LITTLEENDIAN__.
You will also need to change all mentions of qcc to aarch64-unknown-nto-qnx7.1.0-gcc. Since qcc is a proprietary
wrapper around gcc, clangd does not recognize it as a proper compiler. However, we can use the underlying gcc target
compiler for aarch64 in order to satisfy clangd instead.
compiledb generated output:
[
{
"directory": "/home/linguini/cuinspace/qnx-stack/fetcher/nto-x86_64-o",
"arguments": [
"/home/linguini/qnx710/host/linux/x86_64/usr/bin/qcc",
"-c",
"-Wall",
"-Wextra",
"-I.",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/nto-x86_64-o",
"-I/home/linguini/cuinspace/qnx-stack/fetcher",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/src",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/src/include",
"-I/home/linguini/qnx710/target/qnx7/usr/include",
"/home/linguini/cuinspace/qnx-stack/fetcher/src/main.c"
],
"file": "/home/linguini/cuinspace/qnx-stack/fetcher/src/main.c"
}
]Your modified output:
[
{
"directory": "/home/linguini/cuinspace/qnx-stack/fetcher/nto-x86_64-o",
"arguments": [
"/home/linguini/qnx710/host/linux/x86_64/usr/bin/aarch64-unknown-nto-qnx7.1.0-gcc",
"-c",
"-Wall",
"-Wextra",
"-I.",
"-D__QNXNTO__",
"-D__LITTLEENDIAN__",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/nto-x86_64-o",
"-I/home/linguini/cuinspace/qnx-stack/fetcher",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/src",
"-I/home/linguini/cuinspace/qnx-stack/fetcher/src/include",
"-I/home/linguini/qnx710/target/qnx7/usr/include",
"/home/linguini/cuinspace/qnx-stack/fetcher/src/main.c"
],
"file": "/home/linguini/cuinspace/qnx-stack/fetcher/src/main.c"
}
]As mentioned, you will also need to update the --query-driver command given to clangd. The easiest way to do this is
to set an environment variable called CLANGD_FLAGS with your query driver flag. See the OS specific subheadings for
this.
You can run python3 -m compiledb make all in the repository directory (do this on a per module basis instead of for
the whole qnx-stack repository) to generate the compile_commands.json file. This will be ignored by git.
To create the CLANGD_FLAGS environment variable, you can run:
export CLANGD_FLAGS="--query-driver=/home/<your username>/qnx710/host/linux/x86_64/usr/bin/*gcc"To make this persistent, use this same command in your .bashrc file. It should be located within your home directory.
You can run py -m compiledb make all in the repository directory (do this on a per module basis instead of for the
whole qnx-stack repository) to generate the compile_commands.json file. This will be ignored by git.
To create the CLANGD_FLAGS environment variable, open the System Properties window (from the search bar), and click
Environment Variables.
Under either one of your system or user variables, click New. The variable name will be CLANGD_FLAGS and the value
will be something like --query-driver=C:/Users/<your username>/qnx710/host/win64/x86_64/usr/bin/*gcc. Click Ok. If
you already had a terminal open, you will need to use refreshenv for this to take into effect, or close and reopen
your terminal.
Just follow the Linux configuration steps.
In order to test on the Raspberry Pi, you will need to transfer the module binaries to it (as well as all files used for testing). Then you will need to log in to the Pi and actually run your tests.
There are two ways to upload binaries to the Raspberry Pi. The first way is through the QNX Momentics IDE, and the second is via SSH.
The QNX Momentics IDE is, quite frankly, terrible. This method of uploading binaries is not recommended for that reason.
- Open the QNX Momentics IDE
- Right click on the project explorer window and select
Import - Choose the "C/C++" folder and select the type of "C/C++ Executable". Click next.
- Your binary parser will be "Elf parser". Browse for your executable. You'll want to select the
nto-aarch64-o.lebinary from the module's repository directory. If it's not there, make sure you've runmake all. - Leave the defaults.
- Click finish.
Repeat the steps above for each binary you want to transfer to the Pi. You'll only have to import each one once, they will update when you recompile.
You will see all the binaries listed in the project explorer window. To upload one to the Pi, do the following:
- Expand the project folder to see the "module name - [aarc64/le]" with the bug icon next to it.
- Right click that binary and select "C/C++ QNX Application".
- Select a target. If you haven't already configured one, click "New QNX Target" and enter the Pi's IP which you found
by running
ifconfigon the Pi.
The binary should run on the Pi and its output (if it has any) will appear in a pop-up console window. By default, the
IDE uploads the binary to /tmp under the root user. It also removes the binary as soon as it finishes running. You
will need to change this.
- Right click on the binary again and select "Debug As" -> "Debug Configurations"
- Navigate to the "Upload" tab
- Scroll to the bottom of the window (using the scrollbar) and uncheck "Remove uploaded components after session"
Now when you run the binary, it should remain on the Pi in the /tmp folder.
This is the preferred upload method since it doesn't require the Momentics IDE, which is bulky. It can also be done from the terminal alongside development.
For both Windows and Linux, you can get a root shell on the Raspberry Pi using the shh command using
ssh root@<pi ip>, where <pi ip> is the IP address of the Raspberry Pi (obtained by running ifconfig on the Pi).
You will be prompted if you want to continue connecting. Enter yes. You will be asked for the root password. If
you're not sure what the root password is, consult the build file in the qnx-guide repository. It should
be mentioned over the /etc/shadow file's definition.
You will then receive a root shell. Multiple users can have a root shell, so you may develop in parallel with other members.
You may need to provide the port to connect to as well (if your terminal does nothing after you run the ssh command above), which you can do by adding -p 12001 to the above command.
In order to transfer files, you will use the scp command.
You will need to run scp -O <local file> root@<pi ip>:/<destination>. This will transfer your local file to the
destination on the Pi. The destination can be a directory, or it can be a new file name/path if you want to change the
file name. Consult the man pages for more information.
The -O option is used to specify the legacy SCP protocol, which is what the Pi uses.
You will need to run scp <local file> root@<pi ip>:/<destination>. This will transfer your local file to the
destination on the Pi. The destination can be a directory, or it can be a new file name/path if you want to change the
file name. You may need to use the -O option, like with Linux or Mac.
If you don't have the scp command on your machine, you may need to install PuTTY.
You will need to run scp -O <local file> root@<pi ip>:/<destination>. This will transfer your local file to the
destination on the Pi. The destination can be a directory, or it can be a new file name/path if you want to change the
file name. Consult the man pages for more information.
The -O option is used to specify the legacy SCP protocol, which is what the Pi uses.
In the qnx-stack directory, you can run the command make deploy HOST=<pi ip> PORT=<port number> (where the port is 12001 currently). You can combine this with the make command to make all your projects and deploy them to the Pi under /tmp/<user>, where user will be the user you're logged in as on your local machine.
If you want to make a subproject and deploy it in one line, you could use the command make <subproject> && make deploy HOST=<pi ip> PORT=<port>. For example, if you were logged in as the user "abcde" and run the command make fetcher && make deploy HOST=111.111.111.111 PORT=12001, that would deploy a compiled binary for fetcher to /tmp/abcde/fetcher. You can then use ssh to connect to the Pi, and the command /tmp/abcde/fetcher will run the program.