0%

In this article, we will explain the difference between the following code snippets:

1
class derived : public base
1
class derived : base

When defining a derived class in C++ that inherits from a base class, you have two different syntaxes to choose from: class derived : public base and class derived : base. These syntaxes determine the type of inheritance and have a significant impact on the accessibility of the base class members in the derived class.

It is customary to see the public specifier used while inheriting a base class.

Public Inheritance: class derived : public base

The syntax class derived : public base represents public inheritance. With public inheritance, the public members of the base class base retain their access levels in the derived class derived. Public members remain accessible as public members, protected members remain accessible as protected members, and private members remain inaccessible. This preserves the original access levels of the base class members.

Private Inheritance: class derived : base

The syntax class derived : base represents private inheritance by default. In private inheritance, both public and protected members of the base class base become private members in the derived class derived. Consequently, they are not directly accessible outside the class. Private members of the base class remain inaccessible as well.

In most scenarios, it is preferred to use the explicit public keyword (class derived : public base) to specify public inheritance. This ensures that the access levels of the base class members are preserved in the derived class, making the code more readable and intuitive.

By understanding the difference between these two inheritance types, you can make informed decisions when designing your class hierarchy in C++.

When working with the & operator in the C language, besides bitwise, its usage is limited to taking the address of a specified variable. However, in C++, the & operator serves two distinct purposes: taking the address of a variable and declaring a reference variable. To understand its purpose, it is crucial to consider the context in which the operator is used.

Taking the Address of a Variable

In C++, the & operator allows you to access the memory location where a variable is stored when used to take the address of a variable. Consider the following example:

1
2
int x = 42;
int* px = &x; // & used to take the address of x

In this case, the & operator is employed to obtain the address of the variable x and assign it to the pointer variable px.

Declaring a Reference Variable

In addition to taking addresses, the & operator can also be used to declare a reference variable. A reference provides an alternative name or alias for an existing variable. Take a look at this example:

1
2
int x = 42;
int& rx = x; // & used to declare the reference variable rx

Here, the & operator is utilized to declare the reference variable rx, which refers to the existing variable x. Any changes made to rx will directly affect the original variable x.

Capturing References in Lambdas

Now, let’s explore an example and determine whether it involves a reference or an address:

1
2
3
4
5
6
void func(uint8_t data)
{
boost::asio::post(io, [&data]() {
// Use the captured 'data' reference here
});
}

Although my instinctive C brain would lean towards determining the address, in the realm of C++, this example demonstrates the concept of capturing references in lambdas. You can refer to the C++ reference documentation for more information.

Lambdas in C++ enable you to capture variables from the surrounding scope. By capturing variables by reference, you can avoid unnecessary data copies and improve performance. In this particular case, the & operator is employed to capture the variable data by reference in the lambda function passed to boost::asio::post. The captured reference to data remains valid throughout the execution of the lambda function.

To ensure the validity of captured references throughout the asynchronous operation, it is crucial to manage their lifespan and avoid accessing invalidated references.

Passing the Address of a Variable to a Lambda

Having covered the topic of capturing references in lambdas, the next question arises: how can we pass the address of a variable to a lambda?

To pass the address of a variable to a lambda, you can utilize the address-of operator & as shown in the following example:

1
2
3
4
5
6
7
void func(uint8_t data)
{
boost::asio::post(io, [&data]() {
// Use the address of 'data' here
std::cout << "data address: " << static_cast<void*>(&data) << std::endl;
});
}

In this example, the lambda captures the variable data by reference and uses the address-of operator & to obtain a pointer to data within the lambda body.

When declaring a member variable in a class, you have the option to declare it as a reference or as a non-reference. Understanding the difference between these two types is crucial, as it affects how they are initialized within the class.

Let’s dive into the dissimilarities between reference and non-reference members through an illustrative example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass {
public:
MyClass(int& ref_val, int non_ref_val) : ref_val_(ref_val), non_ref_val_(non_ref_val) {}

private:
int& ref_val_;
int non_ref_val_;
};

int main() {
int x = 42;
MyClass my_class(x, 10);
return 0;
}

In the given example, we define a class called MyClass featuring two member variables: ref_val_, a reference to an integer, and non_ref_val_, a regular integer.

The key disparity arises in the constructor. The ref_val_ member is initialized in the constructor’s initialization list using the argument ref_val, which is a reference to an integer. This step is essential since a reference must be initialized upon declaration.

One practical application of using reference members is when we want to associate an external object with the class without initializing it inside the class constructor. By initializing the reference member outside the class, we can control the lifetime and initialization of the referenced object separately.

However, it’s crucial to ensure that the lifetime of the referenced object extends beyond the lifetime of the object holding the reference. In this case, if x is going to be used in MyClass, you should ensure that x remains in scope for the entire duration of my_class‘s lifetime. Failure to do so may lead to undefined behavior.

Understanding the difference between reference and non-reference members helps you make informed decisions when designing your classes and ensures the proper usage and management of references within your codebase. It provides flexibility in managing object lifetimes and improves the overall design of your C++ classes.

The PCA954X is a family of I2C multiplexers/switches that allow you to control multiple I2C devices using a single I2C bus. In this section, we will explore how to manually switch between different channels of the PCA954X I2C mux.

Using the i2c-tools

The i2c-tools package provides a set of command-line tools for interacting with I2C devices in Linux. We will be using three main tools: i2cdetect, i2cdump, and i2cset. Make sure you have the i2c-tools package installed on your system before proceeding.

i2cdetect

The i2cdetect tool allows you to scan the I2C bus and detect devices connected to it. It provides a grid view with addresses and corresponding symbols indicating the presence of I2C devices. Here’s an example output:

1
2
3
4
5
6
7
8
9
10
root@albertlin:~# i2cdetect -y 4
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: UU -- -- -- -- -- 16 -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

The symbols used in the output have the following meanings:

  • “–”: The address was probed, but no chip responded.
  • “UU”: Probing was skipped because this address is currently in use by a driver, suggesting the presence of a chip.
  • Hexadecimal address: Indicates the presence of a chip at that address.

i2cdump

The i2cdump tool allows you to read and display the content of registers on an I2C device. You need to provide the bus number and the address of the device you want to dump. Here’s an example usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@albertlin:~# i2cdump -y 4 0x16
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................

This output displays the content of the registers starting from address 0x00.

i2cset

The i2cset tool allows you to set the content of registers on an I2C device. You need to provide the bus number, the address of the device, and the data you want to write. Here’s an example usage:

1
root@albertlin:~# i2cset -y 4 0x70 0x00 0x04

In this example, we are writing the value 0x04 to register address 0x00 of the device at address 0x70 on bus 4.

PCA954X I2C Mux

The PCA954X is a family of I2C multiplexers/switches. You can find the datasheet for PCA9545A/B/C here.

Changing DTS through Yocto

If you’re using Yocto to build your Linux image, you can customize the Linux kernel configuration by following these steps:

  1. Open a terminal and navigate to your Yocto build directory.

  2. Run the following command to enter the Linux kernel menuconfig:

1
bitbake -c menuconfig virtual/kernel
  1. Make the necessary changes in the menuconfig interface. Once you’re

done, save and exit.

  1. Additionally, you can generate a defconfig file by running the following command:
1
bitbake -c savedefconfig virtual/kernel

Writing I2C Mux Device Tree Bindings

To configure the PCA954X I2C mux in the device tree, you can refer to the following documentation:

You can also check out an example of using the PCA954X I2C mux in the device tree in the aspeed-bmc-facebook-minipack.dts file.

Using new_device and delete_device

To add or remove I2C devices dynamically, you can use the new_device and delete_device attributes in the sysfs interface. Here’s an example:

1
2
3
4
5
6
7
root@albertlin:/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a300.i2c-bus/i2c-5/i2c-16/i2c-20# ls
20-0049 20-0056 delete_device i2c-dev mux_device name new_device of_node power subsystem uevent
root@albertlin:/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a300.i2c-bus/i2c-5/i2c-16/i2c-20# echo "0x0049" > delete_device
[ 424.372524] i2c i2c-20: delete_device: Deleting device tmp75 at 0x49
root@albertlin:/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a300.i2c-bus/i2c-5/i2c-16/i2c-20# echo "tmp75 0x49" > new_device
[825617.903108] lm75 20-0049: hwmon2: sensor 'tmp75'
[825617.908643] i2c i2c-20: new_device: Instantiated device tmp75 at 0x49

In the above example, delete_device is used to remove the device with address 0x49, and new_device is used to add a device named “tmp75” at address 0x49.

Reading Kernel Configuration at Runtime

To view the kernel configuration at runtime, you can use the following command:

1
zcat /proc/config.gz

This command will display the configuration options of the running kernel.

Switching PCA954X Channels

To manually switch the channel of an I2C mux, you can use the i2cset command with the appropriate parameters. Here’s an example:

1
2
3
i2cset -y 5 0x70 0x01  # Switch to channel 0
i2cset -y 5 0x70 0x02 # Switch to channel 1
i2cset -y 5 0x70 0x04 # Switch to channel 2

In the above commands, -y 5 specifies the I2C bus number (5 in this case), 0x70 is the address of the I2C mux device, and 0x01, 0x02, and 0x04 are the channel values representing channel 0, channel 1, and channel 2, respectively.

Here’s an example of how you can use these commands:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
root@albertlin:~# i2cset -y 5 0x70 1  # Switch to channel 0
root@albertlin:~# i2cdetect -y 5 # Scan for devices on the I2C bus
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- UU -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 71 -- -- -- -- -- --
root@albertlin:~# i2cset -y 5 0x71 0 # Switch to channel 1
root@albertlin:~# i2cdetect -y 5 # Scan for devices on the I2C bus
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- UU -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- 49 -- -- -- -- -- --
50: -- -- -- -- -- -- 56 -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 71 -- -- -- -- -- --
root@albertlin:~# i2cset -y 5 0x71 2 # Switch to channel 2
root@albertlin:~# i2cdetect -y 5 # Scan for devices on the I2C bus
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- UU -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1f
20: -- -- -- -- -- -- -- -- -- -- -- -- --

-- -- --
30: -- -- 32 -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- 61 -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 71 -- -- -- -- -- --

In the above example, we first switch to channel 0 by using i2cset -y 5 0x70 1, then we scan for devices on the I2C bus using i2cdetect -y 5. After that, we switch to channel 1 with i2cset -y 5 0x71 0 and perform another scan using i2cdetect -y 5. Finally, we switch to channel 2 with i2cset -y 5 0x71 2 and perform a scan again.

OpenBMC utilizes webui-vue as its front-end, which is a single-page application (SPA). Testing the web performance of SPAs can be challenging with traditional tools like Lighthouse, which are typically used for testing static websites. However, Sitespeed.io provides mechanisms to test SPAs, making it a suitable choice for testing the OpenBMC web pages.

Sitespeed.io

Sitespeed.io is a powerful tool that allows you to perform web performance testing on SPAs. It offers the ability to measure various performance metrics and provides detailed insights into the performance of your web application.

Writing a Testing Script

To demonstrate the performance testing of the OpenBMC webui-vue login process, we can refer to the example provided by Sitespeed.io for testing SPAs. You can find the example performance test script for Grafana here. Additionally, the Sitespeed.io documentation provides more information on scripting and available APIs, which you can find here.

For this article, let’s focus on testing the performance of the OpenBMC login process using the provided script openbmc.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module.exports = async function(context, commands) {
await commands.measure.start('https://192.168.0.196/#/login', 'login page');
try {
await commands.addText.byId('root', 'username');
await commands.addText.byId('0penBmc', 'password');

// Start the measurement and give it the alias 'login'
// The alias will be used when the metrics are sent to
// Graphite/InfluxDB
await commands.measure.start('login to dashboard');

// Find the submit button, click it, and wait for the
// page load to complete on the next loaded URL
await commands.click.byXpath('//*[@id="app"]/main/div/div[1]/div/form/button');
await commands.navigate('https://192.168.0.196/#/');

// Stop and collect the metrics
return commands.measure.stop();
} catch (e) {
// If the GUI changes and a link is not there,
// the click commands will throw an error.
// sitespeed.io will catch, log, and rethrow
// and you can choose to handle the error
}
};

Make sure to adjust the URLs and element selectors in the script to match your OpenBMC setup.

With this script, you can measure the performance of the OpenBMC login process using Sitespeed.io. It captures metrics such as page load time, resource timings, and other performance-related data.

Running the Performance Test

To run the performance test on the OpenBMC web pages using the openbmc.js script, you can execute the following command:

1
docker run --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io:27.3.0 openbmc.js --spa --multi -n 1

In this command, the --spa flag indicates that the web page being tested is a single-page application, while the --multi flag enables multiple iterations of the test. The -n 1 argument determines the number of testing iterations to perform. Adjust the value of -n as per your requirements.

For more information on how to customize and extend the performance test, you can refer to the example provided by Sitespeed.io for testing SPAs here.

Video Recording

If you want to have a video recording of the script’s interaction during the performance test, you can specify the --browsertime.videoParams.debug flag. This flag generates a video in the test report, allowing you to visualize the user flow and interactions. Here’s an example command:

1
docker run --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io:27.3.0 openbmc.js --spa --multi --browsertime.videoParams.debug

Make sure to adjust the command and script parameters based on your specific requirements and OpenBMC setup.

By running these commands, you can perform performance testing on the OpenBMC web pages using Sitespeed.io, generate performance metrics, and optionally capture a video recording of the user interaction.

Viewing the Report

Once the performance testing commands have been executed, you can find the generated report in the sitespeed-result folder. The report is presented in the form of an index.html file, which serves as the entry point to access the performance results.

To view the report, navigate to the sitespeed-result folder and open the index.html file in a web browser. This will launch the report and provide you with detailed information about the performance of the OpenBMC web pages.

The report generated by Sitespeed.io includes various metrics such as page load times, resource sizes, network requests, and more. It offers insights into the performance characteristics of the web application, allowing you to identify areas for improvement and optimization.

Make sure to explore the different sections of the report to gain a comprehensive understanding of the performance test results.

Cross Compile

To cross-compile on OpenBMC, follow these steps:

Source the setup script

Start by sourcing the setup script for your target hardware. You can find the script on the OpenBMC GitHub repository. Execute the following command in your terminal:

1
. setup romulus

Build the SDK

Next, build the Software Development Kit (SDK) using the bitbake command. Specify your target as an argument. For example:

1
albertlin@thinkbook:$ bitbake -c populate_sdk obmc-phosphor-image

Install the SDK

Once the SDK is built, you need to install it. Follow these steps:

  1. Create a folder where you want to install the SDK. For instance, let’s use /usr/local/openbmc.

    1
    albertlin@thinkbook:$ sudo mkdir /usr/local/openbmc
  2. Navigate to the directory containing the SDK installation files.

    1
    albertlin@thinkbook:$ cd ./tmp/deploy/sdk/
  3. Run the SDK installation script using the following command:

    1
    2
    3
    albertlin@thinkbook:$ ./oecore-x86_64-armv7ahf-vfpv4d16-toolchain-nodistro.0.sh
    Phosphor OpenBMC (Phosphor OpenBMC Project Reference Distro) SDK installer version nodistro.0
    =============================================================================================
  4. The installation script will prompt you to enter the target directory for the SDK. Specify /usr/local/openbmc when prompted:

    1
    Enter target directory for SDK (default: /usr/local/oecore-x86_64): /usr/local/openbmc
  5. Confirm the installation by typing ‘y’ when asked if you want to proceed:

    1
    2
    3
    4
    5
    You are about to install the SDK to "/usr/local/openbmc". Proceed [Y/n]? y
    Extracting SDK....................................................................................................................................done
    Setting it up...done
    SDK has been successfully set up and is ready to be used.
    Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.
  6. The SDK will be extracted and set up in the specified directory.

  7. Verify that the installation was successful by checking the contents of the installation directory:

    1
    albertlin@thinkbook:$ ls -al /usr/local/openbmc/

Using the SDK

Before compiling your code, you need to set up the SDK environment. Execute the following command to source the environment setup script:

1
albertlin@thinkbook:$ . /usr/local/openbmc/environment-setup-armv7ahf-vfpv4d16-openbmc-linux-gnueabi

Compile

Now you’re ready to compile your code. Here’s an example of compiling a simple “hello” program:

  1. Create a directory for your project and navigate into it.

    1
    2
    albertlin@thinkbook:$ mkdir hello
    albertlin@thinkbook:$ cd hello
  2. Create a C source file named hello.c and a Meson build file named meson.build with the following content:

    hello.c:

    1
    2
    3
    4
    5
    6
    #include <stdio.h>

    int main(void) {
    printf("Hello OpenBMC\n");
    return 0;
    }

    meson.build:

    1
    2
    3
    project('hello', 'c')

    executable('hello', 'hello.c')
  3. Generate the build files using Meson:

    1
    albertlin@thinkbook:hello$ meson build
  4. Build the project using Ninja:

    1
    albertlin@thinkbook:hello$ ninja -C build
  5. Once the build is complete, you can find the compiled binary in the build directory. You can copy it to your OpenBMC target for execution using the scp command:

    1
    albertlin@thinkbook:hello$ scp build/hello root@192.168.0.196:/tmp

Run built program in BMC

To execute the binary on your BMC target, follow these steps:

  1. Connect to your BMC target using SSH.

    1
    ssh root@192.168.0.196
  2. Navigate to the directory where you copied the binary.

    1
    root@romulus:/tmp# cd /tmp
  3. Run the binary.

    1
    2
    root@romulus:/tmp# ./hello
    Hello OpenBMC

That’s it! You have successfully cross-compiled and executed a program on OpenBMC.

Native Build

Source the setup script

Start by sourcing the setup script for your target hardware. You can find the script on the OpenBMC GitHub repository. Execute the following command in your terminal:

1
. setup romulus

Environment Setup and Checking

  1. Check if the required packages listed by sdbusplus are installed:
1
2
sudo apt install git meson libtool pkg-config g++ libsystemd-dev \
python3 python3-pip python3-yaml python3-mako python3-inflection
  1. Check the Boost version used by OpenBMC:

    1
    2
    3
    albertlin@thinkbook:$ bitbake-layers show-recipes | grep -i meson -A 1
    boost:
    boost 1.82.0
  2. Ensure that the Boost version matches what OpenBMC currently use.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    albertlin@albertlin:boost$ wget https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.gz
    --2023-06-17 03:30:56--
    ...
    2023-06-17 03:31:52 (2.52 MB/s) - ‘boost_1_82_0.tar.gz’ saved [142580547/142580547]
    albertlin@albertlin:boost$ ls
    boost_1_82_0.tar.gz

    albertlin@albertlin:boost_1_82_0$ ./bootstrap.sh --prefix=/usr
    Building B2 engine..
    ...
    Further information:

    - Command line help:
    ./b2 --help

    - Getting started guide:
    http://www.boost.org/more/getting_started/unix-variants.html

    - B2 documentation:
    http://www.boost.org/build/

    albertlin@albertlin:boost_1_82_0$ sudo ./b2 --install
    Performing configuration checks
    ...
    The following directory should be added to linker library paths:

    /home/albertlin/hypnoslin/openbmc/boost/boost_1_82_0/stage/lib
    albertlin@albertlin:sdbusplus$ cat /usr/include/boost/version.hpp | grep "BOOST_LIB_VERSION"
    // BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION
    #define BOOST_LIB_VERSION "1_82"

  3. Check the Meson version used by OpenBMC:

1
2
3
albertlin@thinkbook:$ bitbake-layers show-recipes | grep -i meson -A 1
meson:
meta 1.0.1
  1. Ensure that the Meson version matches what OpenBMC currently uses. It’s recommended to have an upgraded version:
1
2
3
4
5
6
7
8
9
10
11
12
13
albertlin@albertlin:sdbusplus$ meson -v
0.61.2
albertlin@albertlin:sdbusplus$ python --version
Python 3.10.6
albertlin@albertlin:sdbusplus$ python -m pip install meson
Defaulting to user installation because normal site-packages is not writeable
Collecting meson
Downloading meson-1.1.1-py3-none-any.whl (918 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 918.4/918.4 KB 2.9 MB/s eta 0:00:00
Installing collected packages: meson
Successfully installed meson-1.1.1
albertlin@thinkbook:~$ meson -v
1.1.1
  1. If there are missing packages reported by Meson while building, install them:
1
sudo apt-get install -y libi2c-dev libarchive-dev libfmt-dev libsystemd-dev
  1. Verify that the GCC/G++ version matches what OpenBMC currently uses.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    albertlin@thinkbook:$ bitbake-layers show-recipes | grep gcc -A 1
    gcc:
    meta 12.2.0
    gcc-cross-arm:
    meta 12.2.0
    gcc-cross-canadian-arm:
    meta 12.2.0
    gcc-crosssdk-x86_64-oesdk-linux:
    meta 12.2.0
    gcc-runtime:
    meta 12.2.0
    gcc-sanitizers:
    meta 12.2.0
    gcc-source-12.2.0:
    meta 12.2.0

    libgcc:
    meta 12.2.0
    libgcc-initial:
    meta 12.2.0
    1
    2
    3
    4
    5
    albertlin@thinkbook:$ gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    ...
    gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04.1)
  2. Ensure that the g++ version matches what OpenBMC currently uses.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    albertlin@albertlin:~$ g++ -v
    Using built-in specs.
    COLLECT_GCC=g++
    ...
    gcc version 9.5.0 (Ubuntu 9.5.0-1ubuntu1~22.04)
    albertlin@albertlin:~$ sudo apt install g++-12
    Reading package lists... Done
    ...
    Processing triggers for man-db (2.10.2-1) ...
    albertlin@albertlin:~$ ls -al /usr/bin/g++
    lrwxrwxrwx 1 root root 5 Mar 20 2020 /usr/bin/g++ -> g++-9
    albertlin@albertlin:~$ sudo rm /usr/bin/g++
    albertlin@albertlin:~$ sudo ln /usr/bin/g++-12 /usr/bin/g++
    albertlin@albertlin:~$ g++ -v
    Using built-in specs.
    COLLECT_GCC=g++
    ...
    gcc version 12.1.0 (Ubuntu 12.1.0-2ubuntu1~22.04)

Building and Executing

  1. Clone the sdbusplus repository. Run the following command:

    1
    2
    git clone https://github.com/openbmc/sdbusplus.git
    cd sdbusplus
  2. Configure the build using Meson. Run the following command:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    albertlin@albertlin:sdbusplus$ meson build -Dtests=disabled -Dexamples=disabled
    The Meson build system
    Version: 1.1.1
    Source dir: /home/albertlin/hypnoslin/openbmc/sdbusplus
    Build dir: /home/albertlin/hypnoslin/openbmc/sdbusplus/build
    Build type: native build
    Project name: sdbusplus
    Project version: 1.0.0
    C compiler for the host machine: cc (gcc 11.3.0 "cc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0")
    C linker for the host machine: cc ld.bfd 2.38
    C++ compiler for the host machine: c++ (gcc 12.1.0 "c++ (Ubuntu 12.1.0-2ubuntu1~22.04) 12.1.0")
    C++ linker for the host machine: c++ ld.bfd 2.38
    Host machine cpu family: x86_64
    Host machine cpu: x86_64
    Found pkg-config: /usr/bin/pkg-config (0.29.2)
    Run-time dependency libsystemd found: YES 249
    Program python3 (inflection, yaml, mako) found: YES (/usr/bin/python3) modules: inflection, yaml, mako
    Run-time dependency Boost found: YES 1.82.0 (/usr/include)
    Program sdbus++ found: YES (/home/albertlin/hypnoslin/openbmc/sdbusplus/tools/sdbus++)
    Program sdbus++ found: YES (overridden)
    Program sdbus++-gen-meson found: YES (/home/albertlin/hypnoslin/openbmc/sdbusplus/tools/sdbus++-gen-meson)
    Program sdbus++-gen-meson found: YES (overridden)
    Build targets in project: 1

    sdbusplus 1.0.0

    User defined options
    examples: disabled
    tests : disabled

    Found ninja-1.10.1 at /usr/bin/ninja
    WARNING: Running the setup command as `meson [options]` instead of `meson setup [options]` is ambiguous and deprecated.
  3. Build the project using Ninja. Run the following command:

    1
    2
    3
    albertlin@albertlin:sdbusplus$ ninja -C build
    ninja: Entering directory `build'
    [11/11] Linking target libsdbusplus.so.1.0.0