Error while mocking zephyr drivers

 Hello,


I'm migrating from NCS v2.1.0 to NCS v2.2.0 and I have some unit tests with Unity and Cmock.

While migrating, I've checked my tests and they don't work anymore.

The problem is that when I try to mock some zephyr drivers files (like led.h, device.h, etc), I have those errors:

/usr/bin/ld: app/libapp.a(cmock_device.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: multiple definition of `__device_dts_ord_14'; app/libapp.a(runner_ihm_test.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: first defined here
/usr/bin/ld: app/libapp.a(cmock_device.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: multiple definition of `__device_dts_ord_15'; app/libapp.a(runner_ihm_test.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: first defined here
/usr/bin/ld: app/libapp.a(cmock_device.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: multiple definition of `__device_dts_ord_10'; app/libapp.a(runner_ihm_test.c.obj):/home/pi/safehear/applications/louis/twister-out/native_posix_64/unity.ihm/mocks/zephyr/device.h:283: first defined here

I've tryed multiple things with no results and it was working on NCS v2.1.0...

Is it possible to help me with this problem ?

Kind regards,

Andrew

  • Hi Andrew, have you compared your devicetree zephyr.dts in NCS 2.1 vs NCS 2.2? Just to verify that no nodes has the same label or similar. 

    Regards

    Runar

  • Hi Runar,

    Here is the zephyr.dts from NCS 2.1

    /dts-v1/;
    
    / {
    	#address-cells = < 0x1 >;
    	#size-cells = < 0x1 >;
    	model = "Native POSIX Board";
    	compatible = "zephyr,posix";
    	chosen {
    		zephyr,console = &uart0;
    		zephyr,shell-uart = &uart0;
    		zephyr,uart-mcumgr = &uart0;
    		zephyr,flash = &flash0;
    		zephyr,entropy = &rng;
    		zephyr,flash-controller = &flashcontroller0;
    		zephyr,ec-host-interface = &hcp;
    		zephyr,display = &sdl_dc;
    		zephyr,canbus = &can_loopback0;
    	};
    	aliases {
    		eeprom-0 = &eeprom0;
    		i2c-0 = &i2c0;
    		spi-0 = &spi0;
    		led0 = &led0;
    	};
    	leds {
    		compatible = "gpio-leds";
    		led0: led_0 {
    			gpios = < &gpio0 0x0 0x0 >;
    			label = "Green LED";
    		};
    	};
    	cpus {
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		cpu0: cpu@0 {
    			compatible = "zephyr,native-posix-cpu";
    			reg = < 0x0 >;
    		};
    	};
    	flashcontroller0: flash-controller@0 {
    		compatible = "zephyr,sim-flash";
    		reg = < 0x0 0x200000 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x1 >;
    		erase-value = < 0xff >;
    		label = "flash_ctrl";
    		flash0: flash@0 {
    			status = "okay";
    			compatible = "soc-nv-flash";
    			label = "flash";
    			erase-block-size = < 0x1000 >;
    			write-block-size = < 0x1 >;
    			reg = < 0x0 0x200000 >;
    			partitions {
    				compatible = "fixed-partitions";
    				#address-cells = < 0x1 >;
    				#size-cells = < 0x1 >;
    				boot_partition: partition@0 {
    					label = "mcuboot";
    					reg = < 0x0 0xc000 >;
    				};
    				slot0_partition: partition@c000 {
    					label = "image-0";
    					reg = < 0xc000 0x69000 >;
    				};
    				slot1_partition: partition@75000 {
    					label = "image-1";
    					reg = < 0x75000 0x69000 >;
    				};
    				scratch_partition: partition@de000 {
    					label = "image-scratch";
    					reg = < 0xde000 0x1e000 >;
    				};
    				storage_partition: partition@fc000 {
    					label = "storage";
    					reg = < 0xfc000 0x4000 >;
    				};
    			};
    		};
    	};
    	eeprom0: eeprom {
    		status = "okay";
    		compatible = "zephyr,sim-eeprom";
    		label = "EEPROM_0";
    		size = < 0x8000 >;
    	};
    	i2c0: i2c@100 {
    		status = "okay";
    		compatible = "zephyr,i2c-emul-controller";
    		clock-frequency = < 0x186a0 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		reg = < 0x100 0x4 >;
    		label = "I2C_0";
    	};
    	spi0: spi@200 {
    		status = "okay";
    		compatible = "zephyr,spi-emul-controller";
    		clock-frequency = < 0x2faf080 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		reg = < 0x200 0x4 >;
    		label = "SPI_0";
    	};
    	espi0: espi@300 {
    		status = "okay";
    		compatible = "zephyr,espi-emul-controller";
    		reg = < 0x300 0x4 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		label = "ESPI_0";
    	};
    	uart0: uart {
    		status = "okay";
    		compatible = "zephyr,native-posix-uart";
    		label = "UART_0";
    		current-speed = < 0x0 >;
    	};
    	uart1: uart_1 {
    		status = "okay";
    		compatible = "zephyr,native-posix-uart";
    		label = "UART_1";
    		current-speed = < 0x0 >;
    	};
    	rng: rng {
    		status = "okay";
    		compatible = "zephyr,native-posix-rng";
    		label = "ENTROPY_0";
    	};
    	counter0: counter {
    		status = "okay";
    		compatible = "zephyr,native-posix-counter";
    		label = "COUNTER_0";
    	};
    	hcp: ec-host-cmd-periph {
    		status = "okay";
    		compatible = "zephyr,sim-ec-host-cmd-periph";
    		label = "EC_HOST_CMD_SIM";
    	};
    	gpio0: gpio@800 {
    		status = "okay";
    		compatible = "zephyr,gpio-emul";
    		label = "GPIO_0";
    		reg = < 0x800 0x4 >;
    		rising-edge;
    		falling-edge;
    		high-level;
    		low-level;
    		gpio-controller;
    		#gpio-cells = < 0x2 >;
    		phandle = < 0x1 >;
    	};
    	zephyr_udc0: udc0 {
    		compatible = "zephyr,native-posix-udc";
    		label = "USBD";
    	};
    	sdl_dc: sdl_dc {
    		compatible = "zephyr,sdl-dc";
    		label = "SDL display controller";
    		height = < 0xf0 >;
    		width = < 0x140 >;
    	};
    	can_loopback0: can_loopback0 {
    		status = "disabled";
    		compatible = "zephyr,can-loopback";
    		label = "CAN_LOOPBACK_0";
    		sjw = < 0x1 >;
    		sample-point = < 0x36b >;
    		bus-speed = < 0x1e848 >;
    	};
    };

    And here is the one from NCS 2.2:

    /dts-v1/;
    
    / {
    	#address-cells = < 0x1 >;
    	#size-cells = < 0x1 >;
    	model = "Native POSIX Board";
    	compatible = "zephyr,posix";
    	chosen {
    		zephyr,console = &uart0;
    		zephyr,shell-uart = &uart0;
    		zephyr,uart-mcumgr = &uart0;
    		zephyr,flash = &flash0;
    		zephyr,entropy = &rng;
    		zephyr,flash-controller = &flashcontroller0;
    		zephyr,ec-host-interface = &hcp;
    		zephyr,display = &sdl_dc;
    		zephyr,canbus = &can_loopback0;
    		zephyr,keyboard-scan = &sdl_kscan;
    	};
    	aliases {
    		eeprom-0 = &eeprom0;
    		i2c-0 = &i2c0;
    		spi-0 = &spi0;
    		led0 = &led0;
    		kscan0 = &sdl_kscan;
    	};
    	leds {
    		compatible = "gpio-leds";
    		led0: led_0 {
    			gpios = < &gpio0 0x0 0x0 >;
    			label = "Green LED";
    		};
    	};
    	cpus {
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		cpu0: cpu@0 {
    			compatible = "zephyr,native-posix-cpu";
    			reg = < 0x0 >;
    		};
    	};
    	flashcontroller0: flash-controller@0 {
    		compatible = "zephyr,sim-flash";
    		reg = < 0x0 0x200000 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x1 >;
    		erase-value = < 0xff >;
    		flash0: flash@0 {
    			status = "okay";
    			compatible = "soc-nv-flash";
    			erase-block-size = < 0x1000 >;
    			write-block-size = < 0x1 >;
    			reg = < 0x0 0x200000 >;
    			partitions {
    				compatible = "fixed-partitions";
    				#address-cells = < 0x1 >;
    				#size-cells = < 0x1 >;
    				boot_partition: partition@0 {
    					label = "mcuboot";
    					reg = < 0x0 0xc000 >;
    				};
    				slot0_partition: partition@c000 {
    					label = "image-0";
    					reg = < 0xc000 0x69000 >;
    				};
    				slot1_partition: partition@75000 {
    					label = "image-1";
    					reg = < 0x75000 0x69000 >;
    				};
    				scratch_partition: partition@de000 {
    					label = "image-scratch";
    					reg = < 0xde000 0x1e000 >;
    				};
    				storage_partition: partition@fc000 {
    					label = "storage";
    					reg = < 0xfc000 0x4000 >;
    				};
    			};
    		};
    	};
    	eeprom0: eeprom {
    		status = "okay";
    		compatible = "zephyr,sim-eeprom";
    		size = < 0x8000 >;
    	};
    	i2c0: i2c@100 {
    		status = "okay";
    		compatible = "zephyr,i2c-emul-controller";
    		clock-frequency = < 0x186a0 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		reg = < 0x100 0x4 >;
    	};
    	spi0: spi@200 {
    		status = "okay";
    		compatible = "zephyr,spi-emul-controller";
    		clock-frequency = < 0x2faf080 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		reg = < 0x200 0x4 >;
    	};
    	espi0: espi@300 {
    		status = "okay";
    		compatible = "zephyr,espi-emul-controller";
    		reg = < 0x300 0x4 >;
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    	};
    	uart0: uart {
    		status = "okay";
    		compatible = "zephyr,native-posix-uart";
    		current-speed = < 0x0 >;
    	};
    	uart1: uart_1 {
    		status = "okay";
    		compatible = "zephyr,native-posix-uart";
    		current-speed = < 0x0 >;
    	};
    	rng: rng {
    		status = "okay";
    		compatible = "zephyr,native-posix-rng";
    	};
    	counter0: counter {
    		status = "okay";
    		compatible = "zephyr,native-posix-counter";
    	};
    	hcp: ec-host-cmd-periph {
    		status = "okay";
    		compatible = "zephyr,sim-ec-host-cmd-periph";
    	};
    	gpio0: gpio@800 {
    		status = "okay";
    		compatible = "zephyr,gpio-emul";
    		reg = < 0x800 0x4 >;
    		rising-edge;
    		falling-edge;
    		high-level;
    		low-level;
    		gpio-controller;
    		#gpio-cells = < 0x2 >;
    		phandle = < 0x1 >;
    	};
    	zephyr_udc0: udc0 {
    		compatible = "zephyr,native-posix-udc";
    	};
    	sdl_dc: sdl_dc {
    		compatible = "zephyr,sdl-dc";
    		height = < 0xf0 >;
    		width = < 0x140 >;
    	};
    	sdl_kscan: sdl_kscan {
    		compatible = "zephyr,sdl-kscan";
    	};
    	can_loopback0: can_loopback0 {
    		status = "okay";
    		compatible = "zephyr,can-loopback";
    		sjw = < 0x1 >;
    		sample-point = < 0x36b >;
    		bus-speed = < 0x1e848 >;
    	};
    	can0: can {
    		status = "disabled";
    		compatible = "zephyr,native-posix-linux-can";
    		host-interface = "zcan0";
    		sjw = < 0x1 >;
    		sample-point = < 0x36b >;
    		bus-speed = < 0x1e848 >;
    	};
    };
    

    Both of them are for the same project. Except for the labels removed because of deprecation, there is no major difference.

    Regards,

    Andrew

  • Hi Andrew,

    I am able to reproduce this issue in the example unit test (nrf/tests/unity/example_test) by mocking Zephyr APIs. There are some changes to Unity in v2.2.0, such as changing from __wrap t __cmock and replacing the --wrap compiler option with --defsym, so the problem might be related to these. So far I have not been able to figure out exactly what the issue is, but I have asked the developers about this. I am still waiting on a response, so I will get back to you.

    Best regards,

    Marte

  • Hi Andrew,

    I have gotten a response from the developers. The issue is due to some changes in Zephyr, in particular these lines that have been added to include/zephyr/device.h:

    #if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__)
    /**
     * @brief Declare a device for each status "okay" devicetree node.
     *
     * @note Disabled nodes should not result in devices, so not predeclaring these
     * keeps drivers honest.
     *
     * This is only "maybe" a device because some nodes have status "okay", but
     * don't have a corresponding @ref device allocated. There's no way to figure
     * that out until after we've built the zephyr image, though.
     */
    #define Z_MAYBE_DEVICE_DECLARE_INTERNAL(node_id)                               \
        extern const struct device DEVICE_DT_NAME_GET(node_id);
     
    DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_DEVICE_DECLARE_INTERNAL)
    #endif /* CONFIG_HAS_DTS */
    

    They suggest a possible workaround, as long as you are not interested in mocking the entire Zephyr driver files but rather to get the test to compile so that you can test out other parts of your logic. In that case, you can try to create minimal copies of the Zephyr drivers (device.h, led.h, dsp.h, settings,h, and sensor.h), and including these when running the unit test.

    Best regards,

    Marte

  • Hi Marte,

    Thank you for the reply. How do I make them mockable then ?

    I include <zephyr/device.h> in my code so how can I say to unity and cmock to use those minimals copy and not the originals when testing and mocking ?

    Regards,

    Andrew

Related