0

I try to use a serializer model with the azure-iot-sdk-c in multiple files. As long as I use it only in the main file, everything compiles.

But when I declare the model in another header file, use it in the corresponding c file and in the main file, I get a linker error:

CMakeFiles/simplesample_amqp.dir/otherfile.c.o: In function `FromAGENT_DATA_TYPE_ContosoAnemometer':
otherfile.c:(.text+0x1165): multiple definition of `FromAGENT_DATA_TYPE_ContosoAnemometer'
CMakeFiles/simplesample_amqp.dir/simplesample_amqp.c.o:simplesample_amqp.c:(.text+0x1165): first defined here
collect2: error: ld returned 1 exit status
serializer/samples/simplesample_amqp/CMakeFiles/simplesample_amqp.dir/build.make:160: recipe for target 'serializer/samples/simplesample_amqp/simplesample_amqp' failed
make[2]: *** [serializer/samples/simplesample_amqp/simplesample_amqp] Error 1
CMakeFiles/Makefile2:3947: recipe for target 'serializer/samples/simplesample_amqp/CMakeFiles/simplesample_amqp.dir/all' failed
make[1]: *** [serializer/samples/simplesample_amqp/CMakeFiles/simplesample_amqp.dir/all] Error 2

I tried this by adapting the serializer/samples/simplesample_amqp example:

diff --git a/serializer/samples/simplesample_amqp/CMakeLists.txt b/serializer/samples/simplesample_amqp/CMakeLists.txt
index 4f26060..52d55d7 100644
--- a/serializer/samples/simplesample_amqp/CMakeLists.txt
+++ b/serializer/samples/simplesample_amqp/CMakeLists.txt
@@ -11,6 +11,7 @@ endif()

 set(simplesample_amqp_c_files
 simplesample_amqp.c
+otherfile.c
 )

 if(WIN32)
@@ -21,6 +22,7 @@ endif()

 set(simplesample_amqp_h_files
 simplesample_amqp.h
+otherfile.h
 )

 IF(WIN32)
diff --git a/serializer/samples/simplesample_amqp/simplesample_amqp.c b/serializer/samples/simplesample_amqp/simplesample_amqp.c
index 0a9c9a8..b312c9c 100644
--- a/serializer/samples/simplesample_amqp/simplesample_amqp.c
+++ b/serializer/samples/simplesample_amqp/simplesample_amqp.c
@@ -26,24 +26,11 @@
 #include "certs.h"
 #endif // SET_TRUSTED_CERT_IN_SAMPLES

+#include "otherfile.h"
+
 /*String containing Hostname, Device Id & Device Key in the format:             */
 /*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"    */
-static const char* connectionString = "[device connection string]";
-
-// Define the Model
-BEGIN_NAMESPACE(WeatherStation);
-
-DECLARE_MODEL(ContosoAnemometer,
-WITH_DATA(ascii_char_ptr, DeviceId),
-WITH_DATA(int, WindSpeed),
-WITH_DATA(float, Temperature),
-WITH_DATA(float, Humidity),
-WITH_ACTION(TurnFanOn),
-WITH_ACTION(TurnFanOff),
-WITH_ACTION(SetAirResistance, int, Position)
-);
-
-END_NAMESPACE(WeatherStation);
+static const char* connectionString = "";

 static char propText[1024];

@@ -199,10 +186,8 @@ void simplesample_amqp_run(void)
                     }
                     else
                     {
-                        myWeather->DeviceId = "myFirstDevice";
-                        myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2);
-                        myWeather->Temperature = minTemperature + (rand() % 10);
-                        myWeather->Humidity = minHumidity + (rand() % 20);
+                                               myWeather->DeviceId = "myFirstDevice";
+                                               process_model(myWeather);

                         if (SERIALIZE(&destination, &destinationSize, myWeather->DeviceId, myWeather->WindSpeed, myWeather->Temperature, myWeather->Humidity) != CODEFIRST_OK)
                         {

otherfile.h:

// Define the Model
#include "serializer.h"
BEGIN_NAMESPACE(WeatherStation);

DECLARE_MODEL(ContosoAnemometer,
WITH_DATA(ascii_char_ptr, DeviceId),
WITH_DATA(int, WindSpeed),
WITH_DATA(float, Temperature),
WITH_DATA(float, Humidity),
WITH_ACTION(TurnFanOn),
WITH_ACTION(TurnFanOff),
WITH_ACTION(SetAirResistance, int, Position)
);

END_NAMESPACE(WeatherStation);

void process_model(ContosoAnemometer *myWeather);

otherfile.c:

#include "otherfile.h"

void process_model(ContosoAnemometer *myWeather) {
    int avgWindSpeed = 10;
    float minTemperature = 20.0;
    float minHumidity = 60.0;

    myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2);
    myWeather->Temperature = minTemperature + (rand() % 10);
    myWeather->Humidity = minHumidity + (rand() % 20);
}

Is there any way to work with the serializer model in multiple files?

Feel free to ask me for more information, please. Right now I'm not so sure what information is relevant for this post. I tried rigorously with the mqtt serializer example some time ago but got stuck with the same error as far as I can remember. It is really messy if you can not modularize your code and just have one monolithic file containing almost everything.

GCC: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

OS: 4.4.0-97-generic #120-Ubuntu SMP Tue Sep 19 17:28:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

StrawHat
  • 175
  • 1
  • 12

1 Answers1

1

You can't reuse models but you can reuse datastructures. This can help you reuse up to 80% of your definitions. You can design JSON structure as a set of DECLARE_STRUCT like this in separate file:

DECLARE_STRUCT(MyCommon,
   EDM_DATE_TIME_OFFSET, datetime,
   ascii_char_ptr, deviceid, 
   ascii_char_ptr, vin,
   int32_t, message_id, 
   int32_t, request_messageid 
);

After that you can use #include to reuse DECLARE_STRUCT for different models in С files:

BEGIN_NAMESPACE(cctcp);
 #include "MyCommon_json.inc"
DECLARE_MODEL(Message,
  WITH_DATA(EDM_GUID, edge_message_id),  
  WITH_DATA(int8_t, message_type),   
   WITH_DATA(MyCommon, tcu_common)
);