I updated this post on 8/23 to reflect the working solution.
I'm working with the c BACnet Stack on sourceforge. http://sourceforge.net/projects/bacnet/
I'm trying to modify the demo server included in the library. The server does almost exactly what I want it to, except that I need to connect it to some other c programs that I wrote.
My problem right now is that I can't figure out how to add my own c programs into the demo server. There are several nested Makefiles in the demo. I've tried adding my file into these Makefiles, but the compiler (gcc) doesn't like it.
The latest error is:
No rule to make target ../../demo/object/test.o', needed bybacserv'. Stop.
I am not a c expert. I've been working with it my spare time for about a year. I understand the basics of a Makefile, but the Makefiles in this demo are apparently beyond me.
Is there anyone familiar with this library that might give me a little help?
Are there any better documentation than what is on the sourceforge website?
In this example I'm simply trying to add test.c to ai.c.
/demo/server/Makefile
OBJECT_SRC = \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
$(BACNET_OBJECT)/av.c \
$(BACNET_OBJECT)/bi.c \
$(BACNET_OBJECT)/bo.c \
$(BACNET_OBJECT)/bv.c \
$(BACNET_OBJECT)/csv.c \
$(BACNET_OBJECT)/lc.c \
$(BACNET_OBJECT)/lsp.c \
$(BACNET_OBJECT)/ms-input.c \
$(BACNET_OBJECT)/mso.c \
$(BACNET_OBJECT)/msv.c \
$(BACNET_OBJECT)/nc.c \
$(BACNET_OBJECT)/trendlog.c \
$(BACNET_OBJECT)/test.c \ <-- New entry
$(BACNET_OBJECT)/bacfile.c
/lib/Makefile
CORE_SRC = \
$(BACNET_CORE)/apdu.c \
$(BACNET_CORE)/npdu.c \
$(BACNET_CORE)/bacdcode.c \
$(BACNET_CORE)/bacint.c \
$(BACNET_CORE)/bacreal.c \
$(BACNET_CORE)/bacstr.c \
$(BACNET_CORE)/bacapp.c \
$(BACNET_CORE)/bacprop.c \
$(BACNET_CORE)/bactext.c \
$(BACNET_CORE)/datetime.c \
$(BACNET_CORE)/indtext.c \
$(BACNET_CORE)/key.c \
$(BACNET_CORE)/keylist.c \
$(BACNET_CORE)/proplist.c \
$(BACNET_CORE)/debug.c \
$(BACNET_CORE)/bigend.c \
$(BACNET_CORE)/arf.c \
$(BACNET_CORE)/awf.c \
$(BACNET_CORE)/cov.c \
$(BACNET_CORE)/dcc.c \
$(BACNET_CORE)/iam.c \
$(BACNET_CORE)/ihave.c \
$(BACNET_CORE)/rd.c \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/timesync.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c \
$(BACNET_CORE)/wpm.c \
$(BACNET_CORE)/abort.c \
$(BACNET_CORE)/reject.c \
$(BACNET_CORE)/bacerror.c \
$(BACNET_CORE)/ptransfer.c \
$(BACNET_CORE)/memcopy.c \
$(BACNET_CORE)/filename.c \
$(BACNET_CORE)/tsm.c \
$(BACNET_CORE)/bacaddr.c \
$(BACNET_CORE)/address.c \
$(BACNET_CORE)/bacdevobjpropref.c \
$(BACNET_CORE)/bacpropstates.c \
$(BACNET_CORE)/alarm_ack.c \
$(BACNET_CORE)/event.c \
$(BACNET_CORE)/getevent.c \
$(BACNET_CORE)/get_alarm_sum.c \
$(BACNET_CORE)/readrange.c \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/test.c \ <-- Do not include test.c in this Makefile at all
$(BACNET_CORE)/version.c
new file locations:
test.c is located in /src <-- Should be located in /demo/object
test.h is located in /include <-- This works ok here
test.h
#ifndef _TEST_INCLUDE_
#define _TEST_INCLUDE_
void printit();
#endif
test.c
#include <stdio.h> <-- Needed to add #include <stdio.h>
#include "test.h"
void printit (){
printf("it....");
}
/demo/object/ai.c
...
#include "handlers.h"
#include "timestamp.h"
#include "test.h"
#include "ai.h"
...
void Analog_Input_Init(
void)
{
unsigned i;
#if defined(INTRINSIC_REPORTING)
unsigned j;
#endif
printit(); //*****************************************************************
for (i = 0; i < MAX_ANALOG_INPUTS; i++) {
printf("Initializing AI:%u\n",i);
AI_Descr[i].Present_Value = 0.0f;
AI_Descr[i].Out_Of_Service = false;
AI_Descr[i].Units = UNITS_PERCENT;
AI_Descr[i].Reliability = RELIABILITY_NO_FAULT_DETECTED;
#if defined(INTRINSIC_REPORTING)
AI_Descr[i].Event_State = EVENT_STATE_NORMAL;
/* notification class not connected */
AI_Descr[i].Notification_Class = BACNET_MAX_INSTANCE;
/* initialize Event time stamps using wildcards
and set Acked_transitions */
for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) {
datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]);
AI_Descr[i].Acked_Transitions[j].bIsAcked = true;
}
/* Set handler for GetEventInformation function */
handler_get_event_information_set(OBJECT_ANALOG_INPUT,
Analog_Input_Event_Information);
/* Set handler for AcknowledgeAlarm function */
handler_alarm_ack_set(OBJECT_ANALOG_INPUT, Analog_Input_Alarm_Ack);
/* Set handler for GetAlarmSummary Service */
handler_get_alarm_summary_set(OBJECT_ANALOG_INPUT,
Analog_Input_Alarm_Summary);
#endif
}
}
I would say that your test.o cannot be made by gcc. The Makefile does specify to create it, though :
.c.o:
${CC} -c ${CFLAGS} $*.c -o $#
I noticed that $(BACNET_OBJECT) in /demo/server/Makefile refers to the path /demo/object
You should try to add test.c there.
And i believe you don't need to add test.c in /lib/Makefile
Long time i didnt do any C, but didnt you forget to #include <stdio.h> for printf in test.c ?
Related
I'm playing around with building a psuedo-generic type in C. Essentially, I'm trying to clone Rust's Option<T> with a predefined, constrained list of types allowable as T.
Obviously, C isn't really suited for this -- I'm doing this primarily to see how far I can go (as opposed to something I'd expect to use in real production code). To that end, any ugly hacks are fair game.
What I have so far builds out a separate set of inner-type-specific functions for all provided types. It looks something like this:
Header:
#pragma once
#define ALL_OPTIONS \
OPTION_INSTANCE(option_bool, bool) \
OPTION_INSTANCE(option_double, double) \
OPTION_INSTANCE(option_int, int)
#define OPTION_INSTANCE(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t;
ALL_OPTIONS
#undef OPTION_INSTANCE
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self); \
ALL_OPTIONS
#undef OPTION_INSTANCE
Implementation:
#include "option.h"
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
\
name##_t name##_none(void) { \
return (name##_t) { \
.is_some = false, \
}; \
} \
\
bool name##_is_some(name##_t self) { \
return self.is_some; \
} \
\
bool name##_is_none(name##_t self) { \
return !self.is_some; \
}
ALL_OPTIONS
#undef OPTION_INSTANCE
Note that in my actual code I have many more functions defined for the generated types.
This works well enough, though primarily all I've done is reduce implementation boilerplate. The next step would be to implement option_is_some (no type qualification) which can accept any option_<inner>_t
I can do that well enough with a manual macro, leveraging C11 generics:
#define option_is_some(self) \
_Generic((self), \
option_bool_t: option_bool_is_some, \
option_double_t: option_double_is_some, \
option_int_t: option_int_is_some, \
)(self)
but this necessarily duplicates the list of types defined in ALL_OPTIONS. What I'd really like to do would be something like
#define OPTION_INSTANCE(name, inner) \
name##_t: name##_is_some,
#define option_is_some(self) \
_Generic((self), \
ALL_OPTIONS \
default: false \
)(self)
#undef OPTION_INSTANCE
but that fails, since ALL_OPTIONS is expanded when option_is_some is used (where OPTION_INSTANCE will be undefined).
So, I'm looking for alternatives. I'd happily move to a radically different method of defining a generic list of types (instead of the ALL_OPTIONS hack) -- however, I do want to preserve the property that adding a new supported inner type only requires a change in a single location.
Just access the member in the macro itself:
#define option_is_some(self) ((self).is_some)
Overall, your implementation is strange. Do not have a central ALL_OPTIONS place - do one option at a time, separately from each other. Files are split into headers and source files in C.
#define OPTION_HEADER(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t; \
\
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self);
#define OPTION_SOURCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
etc...
#define OPTION_HEADER_AND_SOURCE(name, ...) \
OPTION_HEADER(name, __VA_ARGS__)
OPTION_SOURCE(name, __VA_ARGS__)
Then you would just do the options:
OPTION_HEADER_AND_SOURCE(option_bool, bool)
OPTION_HEADER_AND_SOURCE(option_double, double)
OPTION_HEADER_AND_SOURCE(option_int, int)
You can take a look at other projects that I've found: https://github.com/tylov/STC and https://github.com/glouw/ctl that use macro-ish templates to implement in C various container known from C++.
all
My codes like this:
#define TTP_ROUTE_TABLE_ENTRY_INC(table) \
static inline void \
ttp_route_##table_inc(void) \
{ \
cur_l3_##table_table_entries++; \
}
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_host)
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_route)
TTP_ROUTE_TABLE_ENTRY_INC(ipv6_host)
TTP_ROUTE_TABLE_ENTRY_INC(ipv6_route)
#undef TTP_ROUTE_TABLE_ENTRY_INC
but gcc warning:
lib/ttp-route-table.c:130:1: error: redefinition of 'ttp_route_table_inc'
So I think GCC preprocess ##table into table, actually I want
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_host)
will be translate into this:
static inline void \
ttp_route_ipv4_host_inc(void) \
{ \
cur_l3_ipv4_host_table_entries++; \
}
So I don't know what's wrong with my codes. Thank you for your help.
You need another set of # after the argument table:
ttp_route_##table##_inc(void)
The same goes for other lines containing table.
MISRA 19.10:
In the definition of a function-like macro each instance of a parameter shall be enclosed in parentheses unless it is used as the operand of # or ##.
I have a struct defined like this:
typedef struct
{
SUint_t affValueIndex;
const SFloat_t affLoSaturation;
const SFloat_t affHiSaturation;
const SFloat_t affCoeffTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
SFloat_t affValueTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
} SAnalogFloatFilter_t;
Then I do:
#define DEF_ANALOG_FILTER_COEFF_LIST {0.0287421759f, \
0.1225311874f, \
0.2123775504f, \
0.2726981726f, \
0.2123775504f, \
0.1225311874f, \
0.0287421759f}
#define SMK_ANALOG_FLOAT_FILTER_HANDLE(__name__, __coeff_list__, __hi_sat__, __low_sat__) \
SAnalogFloatFilter_t (__name__)[1] = {{0u, (__low_sat__), (__hi_sat__), __coeff_list__ , {(SFloat_t)0,}}}
static SMK_ANALOG_FLOAT_FILTER_HANDLE(CurrMonFilter,
DEF_ANALOG_FILTER_COEFF_LIST,
(SFloat_t)DEF_ANALOG_FILTER_HI_SAT,
(SFloat_t)DEF_ANALOG_FILTER_LO_SAT);
The problem is that the __ coeff_list __ parameter cannot have a parenthesis as it then expands to ({...}) (an array initialilser), to which the gcc complains:
foo.c:45:9: error: statement-expressions are not allowed outside functions nor in template-argument lists
Is there a clever way to keep the MISRA 19.10 check AND have an array initialiser in the SMK_ANALOG_FLOAT_FILTER_HANDLE macro?
This compiles for me:
typedef int SUint_t;
typedef float SFloat_t;
#define SDEF_ANALOG_FLOAT_FILTER_LEN 8
typedef struct
{
SUint_t affValueIndex;
const SFloat_t affLoSaturation;
const SFloat_t affHiSaturation;
const SFloat_t affCoeffTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
SFloat_t affValueTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
} SAnalogFloatFilter_t;
#define DEF_ANALOG_FILTER_COEFF_LIST (const SFloat_t[SDEF_ANALOG_FLOAT_FILTER_LEN]) \
{0.0287421759f, \
0.1225311874f, \
0.2123775504f, \
0.2726981726f, \
0.2123775504f, \
0.1225311874f, \
0.0287421759f}
#define SMK_ANALOG_FLOAT_FILTER_HANDLE(__name__, __coeff_list__, __hi_sat__, __low_sat__) \
SAnalogFloatFilter_t (__name__)[1] = {{0u, (__low_sat__), (__hi_sat__), (__coeff_list__) , {(SFloat_t)0,}}}
#define DEF_ANALOG_FILTER_HI_SAT 0.0f
#define DEF_ANALOG_FILTER_LO_SAT 0.0f
static SMK_ANALOG_FLOAT_FILTER_HANDLE(CurrMonFilter,
DEF_ANALOG_FILTER_COEFF_LIST,
(SFloat_t)DEF_ANALOG_FILTER_HI_SAT,
(SFloat_t)DEF_ANALOG_FILTER_LO_SAT);
Tested on Ubuntu 12.04.03 LTS with commands:
gcc-4.6 -c -o foo.o foo.c
and
gcc-4.8 -c -o foo.o foo.c
when i try to compile i got tons of those error :
km6502ot.h:77:1: error: pasting "Opcodei" and "(" does not give a valid preprocessing token
I'm on OSX, i can solve it by doing it manually for all possibilities but is it possible to fix this macro so gcc would eat it peacefully :
#define OP__(i) \
case 0x##i##: \
Opcode##i##(__THISP); \
break;
#define OP_d(i) \
case 0x##i##: \
if (__THIS__.P & D_FLAG) \
D_Opco##i##(__THISP); \
else \
Opcode##i##(__THISP); \
break;
try this
#define OP__(i) \
case 0x##i : \
Opcode##i (__THISP); \
break;
#define OP_d(i) \
case 0x##i : \
if (__THIS__.P & D_FLAG) \
D_Opco##i (__THISP); \
else \
Opcode##i (__THISP); \
break;
I have a makefile (intended for nmake) with the following contents.
w = \
abort_.obj \
backspac.obj \
c_abs.obj \
c_cos.obj \
c_div.obj \
c_exp.obj \
c_log.obj \
c_sin.obj \
c_sqrt.obj \
cabs.obj \
close.obj \
d_abs.obj \
d_acos.obj \
d_asin.obj \
d_atan.obj \
d_atn2.obj \
d_cnjg.obj \
d_cos.obj \
d_cosh.obj \
d_dim.obj \
d_exp.obj \
d_imag.obj \
d_int.obj \
d_lg10.obj \
d_log.obj \
d_mod.obj \
d_nint.obj \
d_prod.obj \
d_sign.obj \
d_sin.obj \
d_sinh.obj \
d_sqrt.obj \
d_tan.obj \
d_tanh.obj \
derf_.obj \
derfc_.obj \
dfe.obj \
dolio.obj \
dtime_.obj \
due.obj \
ef1asc_.obj \
ef1cmc_.obj \
endfile.obj \
erf_.obj \
erfc_.obj \
err.obj \
etime_.obj \
exit_.obj \
f77_aloc.obj \
f77vers.obj \
fmt.obj \
fmtlib.obj \
ftell_.obj \
getarg_.obj \
getenv_.obj \
h_abs.obj \
h_dim.obj \
h_dnnt.obj \
h_indx.obj \
h_len.obj \
h_mod.obj \
h_nint.obj \
h_sign.obj \
hl_ge.obj \
hl_gt.obj \
hl_le.obj \
hl_lt.obj \
i77vers.obj \
i_abs.obj \
i_dim.obj \
i_dnnt.obj \
i_indx.obj \
i_len.obj \
i_mod.obj \
i_nint.obj \
i_sign.obj \
iargc_.obj \
iio.obj \
ilnw.obj \
inquire.obj \
l_ge.obj \
l_gt.obj \
l_le.obj \
l_lt.obj \
lbitbits.obj \
lbitshft.obj \
lread.obj \
lwrite.obj \
main.obj \
open.obj \
pow_ci.obj \
pow_dd.obj \
pow_di.obj \
pow_hh.obj \
pow_ii.obj \
pow_ri.obj \
pow_zi.obj \
pow_zz.obj \
r_abs.obj \
r_acos.obj \
r_asin.obj \
r_atan.obj \
r_atn2.obj \
r_cnjg.obj \
r_cos.obj \
r_cosh.obj \
r_dim.obj \
r_exp.obj \
r_imag.obj \
r_int.obj \
r_lg10.obj \
r_log.obj \
r_mod.obj \
r_nint.obj \
r_sign.obj \
r_sin.obj \
r_sinh.obj \
r_sqrt.obj \
r_tan.obj \
r_tanh.obj \
rdfmt.obj \
rewind.obj \
rsfe.obj \
rsli.obj \
rsne.obj \
s_cat.obj \
s_cmp.obj \
s_copy.obj \
s_paus.obj \
s_rnge.obj \
s_stop.obj \
sfe.obj \
sig_die.obj \
signal_.obj \
sue.obj \
system_.obj \
typesize.obj \
uio.obj \
uninit.obj \
util.obj \
wref.obj \
wrtfmt.obj \
wsfe.obj \
wsle.obj \
wsne.obj \
xwsne.obj \
z_abs.obj \
z_cos.obj \
z_div.obj \
z_exp.obj \
z_log.obj \
z_sin.obj \
z_sqrt.obj
-----------snip----------------------------
vcf2c.lib: $w
lib -out:vcf2c.lib #libf2c.lbc
What does the # in front of, "libf2c.lbc," do? In a batch file # suppresses output but I don't see how that applies.
It's a LIB command file. As described on the page I linked:
You can pass command-line arguments to LIB in a command file using the
following syntax:
LIB #commandfile
The file commandfile is a text file. No space or tab is allowed
between the at sign (#) and the file name. There is no default
extension; you must specify the full file name, including any
extension. Wildcards cannot be used. You can specify an absolute or
relative path with the file name.
In the command file, arguments can be separated by spaces or tabs, as
they can on the command line; they can also be separated by newline
characters. Use a semicolon (;) to mark a comment. LIB ignores all
text from the semicolon to the end of the line.
You can specify either all or part of the command line in a command
file, and you can use more than one command file in a LIB command. LIB
accepts the command-file input as if it were specified in that
location on the command line. Command files cannot be nested. LIB
echoes the contents of command files unless the /NOLOGO option is
used.
It's a common convention on some systems (but not universally supported on any system) that a filename preceded by an # means that the program should read the contents of the file and interpret the contents as arguments to the program.
So in your case, the lib program will read in the file libf2c.lbc and use its contents as arguments.
I guess it's possible that this is a feature of nmake, I don't know much about nmake. It's certainly not part of any "traditional" make program.