ThrowTheSwitch / CMock

CMock - Mock/stub generator for C
http://throwtheswitch.org
MIT License
653 stars 269 forks source link

CMock 'Failed Parsing Declaration Prototype!' on updated header in Zephyr 3.0.0 #424

Closed drjensbd closed 3 months ago

drjensbd commented 1 year ago

Hello! I have a header from the Zephyr library, 'i2c.h' which has recently been updated with Zephyr 3.0.0. Now, CMock fails to parse this file due to macros in the header. These are the macros in question:

#if defined(CONFIG_I2C_STATS) || defined(__DOXYGEN__)

#include <stats/stats.h>

/** @cond INTERNAL_HIDDEN */

STATS_SECT_START(i2c)
STATS_SECT_ENTRY32(bytes_read)
STATS_SECT_ENTRY32(bytes_written)
STATS_SECT_ENTRY32(message_count)
STATS_SECT_ENTRY32(transfer_call_count)
STATS_SECT_END;

STATS_NAME_START(i2c)
STATS_NAME(i2c, bytes_read)
STATS_NAME(i2c, bytes_written)
STATS_NAME(i2c, message_count)
STATS_NAME(i2c, transfer_call_count)
STATS_NAME_END(i2c);

/** @endcond */

The error:

(...) cmock/lib/cmock_header_parser.rb:598:in `parse_declaration': Failed Parsing Declaration Prototype! (RuntimeError)
  declaration: 'STATS_NAME_START(i2c)STATS_NAME(i2c, bytes_read)STATS_NAME(i2c, bytes_written)STATS_NAME(i2c, message_count)STATS_NAME(i2c, transfer_call_count)STATS_NAME_END(i2c)'
  modifier: ''
  return: {:type => '', :name => 'cmock_to_return', :str => ' cmock_to_return', :void? => false, :ptr? => false, :const? => false, :const_ptr? => false}
  function: 'STATS_NAME_START'
  args: [
    {:ptr? => false, :const? => false, :const_ptr? => false, :name => 'cmock_arg1', :type => 'i2c)STATS_NAME(i2c'}
    {:ptr? => false, :const? => false, :const_ptr? => false, :name => 'cmock_arg2', :type => 'bytes_read)STATS_NAME(i2c'}
    {:ptr? => false, :const? => false, :const_ptr? => false, :name => 'cmock_arg3', :type => 'bytes_written)STATS_NAME(i2c'}
    {:ptr? => false, :const? => false, :const_ptr? => false, :name => 'cmock_arg4', :type => 'message_count)STATS_NAME(i2c'}
    {:ptr? => false, :const? => false, :const_ptr? => false, :name => 'cmock_arg5', :type => 'transfer_call_count)STATS_NAME_END(i2c'}
  ] (...)

CMock seems to interpret the multiline statements as a single function, and fails. The macros are enclosed in an #if defined block, is there a way to run preprocessing on the header before CMock attempts to parse?

Or are there any other ways to solve this?

mvandervoord commented 3 months ago

First, I'm sorry no one answered this in a timely manner.

For those coming to this issue: If you're using Ceedling, you can just enable the preprocessor option. If not, you'd have to preprocess the file yourself before calling CMock. We hope to someday have a full C parser built into C which allows for this sort of feature. This is already captured in other issues, so I'm closing this one.