CPP GPIO control on Beaglebone Black

I have a CPP app which I have recently ported to the Beaglebone Black.
I have my serial ports working and a DS1307 RTC on i2c1 working.
The last hurdle is driving GPIO.
I have read a few articles / solution for GPIO access but would like to know what is the current best practice for this.
I have tried the following:

This works but is a little heavy for my needs as I just want simple GPIO input and output. Also it must run as superuser

This looks a lot lighter and better suited to my needs, but I can’t get it to link. eg

debian@beaglebone:~/supervisor/src$ g++ -std=c++17 -lstdc++fs gpio/*.cpp gpio/*.h main.cpp -o example

/usr/bin/ld: /tmp/ccUoHgBs.o: in function `beagle::gpio::GPIOManager::GPIOManager()':
manager.cpp:(.text+0x138): undefined reference to `std::filesystem::__cxx11::directory_iterator::operator*() const'
/usr/bin/ld: manager.cpp:(.text+0x20c): undefined reference to `std::filesystem::__cxx11::directory_iterator::operator++()'
/usr/bin/ld: /tmp/ccUoHgBs.o: in function `std::filesystem::__cxx11::directory_iterator::directory_iterator(std::filesystem::__cxx11::path const&)':
manager.cpp:(.text._ZNSt10filesystem7__cxx1118directory_iteratorC2ERKNS0_4pathE[_ZNSt10filesystem7__cxx1118directory_iteratorC5ERKNS0_4pathE]+0x12): undefined reference to `std::filesystem::__cxx11::directory_iterator::directory_iterator(std::filesystem::__cxx11::path const&, std::filesystem::directory_options, std::error_code*)'
/usr/bin/ld: /tmp/ccUoHgBs.o: in function `std::filesystem::__cxx11::path::path<char [16], std::filesystem::__cxx11::path>(char const (&) [16], std::filesystem::__cxx11::path::format)':
manager.cpp:(.text._ZNSt10filesystem7__cxx114pathC2IA16_cS1_EERKT_NS1_6formatE[_ZNSt10filesystem7__cxx114pathC5IA16_cS1_EERKT_NS1_6formatE]+0x3a): undefined reference to `std::filesystem::__cxx11::path::_M_split_cmpts()'
collect2: error: ld returned 1 exit status

Thanks for your help.

Is this of any use?

An easy to use, lightweight and very fast library with C API with pinmuxing capability (= no device tree magic, working on any kernel from 3.8 up to the current)

You could look at what Derek Molloy did in Exploring BeagleBone.


Thanks all for your help. I went with zmatts solution (first).
This is simple and works well.
Just one question, is there a table mapping GPIO file numbers eg So far I have found and mapped:

#define P8_11 "/sys/class/gpio/gpio45"
#define P8_12 "/sys/class/gpio/gpio44"
#define P8_13 "/sys/class/gpio/gpio23"
#define P8_14 "/sys/class/gpio/gpio26"


Save this as /etc/udev/rules.d/gpio-symlinks.rules:

SUBSYSTEM=="subsystem", KERNEL=="gpio", ACTION=="add", \
        RUN+="/bin/mkdir -p /dev/gpio"

SUBSYSTEM=="gpio", ACTION=="add", TEST=="value", ATTR{label}!="sysfs", \
        RUN+="/bin/ln -sT '/sys/class/gpio/%k' /dev/gpio/%s{label}"

(be mindful of those two backslashes, they’re important)

Then run sudo update-initramfs -u and reboot, you should have conveniently named symlinks for all exported gpios in /dev/gpio/.

Or if you don’t like adding that udev rule, you can find which gpios map to which expansion header pins in many places, e.g. the P9/P8 tabs of my pins spreadsheet or in the comments in this header.

These list the gpio as X.YY where X is the gpio controller number (0-3) and YY the gpio of that controller (0-31). The kernel gpio number would be calculated as X*32+Y, although it should be mentioned that the kernel technically does not guarantee any particular numbering of gpios, it hands gpio numbers out sequentially to gpio controllers in whatever order they happen to show up. In practice it appears that the registration of “platform” gpio controllers (i.e. those integrated into the SoC) is deterministic hence their gpio numbering is stable, but I personally prefer the udev solution as it simply avoids having to deal with gpio numbers at all.

Thanks Matt