系列文章目录
第二章 安装LinuxCNC
第三章 基于Preempt -RT的IgH EtherCAT Master安装
第四章 基于Xenomai3.1的IgH EtherCAT Master安装
第五章 基于RTAI的IgH EtherCAT Master安装
第六章 修改MakeFile
杂记: Linux配置杂记
目录
前言
修改Igh EtherCAT主站的Makefile,实现基于例子的多文件编译
一、Makefile解析
在还没进行Makefile的修改时,在main函数中添加在test.c中的函数test(),即使已经做好头文件的包含和声明,由于Makefile的编译并没有链接,所以会产生未定义的错误,如图1
![](https://img-blog.csdnimg.cn/4ea6e824922c48f78ba6b40da7b85113.png)
对Makefile的规则进行了解后(1),找到问题的关键在“目标:依赖”这一项中。
对原来的例程进行一次清理和重新生成后,我们可以知道目标的名字是什么,代码如下。
sudo make clean
sudo make
本文的路径为/ethercat_test/examples/dc_user (test),生成的目标名为ec_dc_user_example,因此以此为关键词在Makefile中搜索,可得结果如图2
![](https://img-blog.csdnimg.cn/ff7e0e41d77e4fb488ef3e9c61b43b4c.png)
ec_dc_user_example$(EXEEXT): $(ec_dc_user_example_OBJECTS) $(ec_dc_user_example_DEPENDENCIES) $(EXTRA_ec_dc_user_example_DEPENDENCIES)
@rm -f ec_dc_user_example$(EXEEXT)
$(AM_V_CCLD)$(ec_dc_user_example_LINK) $(ec_dc_user_example_OBJECTS) $(ec_dc_user_example_LDADD) $(LIBS)
对第一行的代码进行解析,第一行代码顶格,从Makefile规则可知此行代码为编译规则,其中
ec_dc_user_example_OBJECTS为ec_dc_user_example-main.o;
ec_dc_user_example_DEPENDENCIES为空;
EXTRA_ec_dc_user_example_DEPENDENCIES为空。
因此该指令为ec_dc_user_examples: ec_dc_user_example-main.o,其中ec_dc_user_example-main.o依赖main.c
第二行代码前方有tab,因此为指令:@rm -f ec_dc_user_example$(EXEEXT),作用是删除已经存在的目标文件
第三行代码前也有tab,因此为指令:$(AM_V_CCLD)$(ec_dc_user_example_LINK) $(ec_dc_user_example_OBJECTS) $(ec_dc_user_example_LDADD) $(LIBS),其中
$(AM_V_CCLD):@echo " CC " $@;
$(ec_dc_user_example_LINK):$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@,再对其中的各个变量进行解析。
$(LIBTOOL) $(AM_V_lt):/bin.bash ../../libtool -silent;
$(AM_LIBTOOLFLAGS)、$(LIBTOOLFLAGS):未定义;
$(CCLD):gcc;
$(AM_CFLAGS):未定义
$(CFLAGS):-g -O2
$(AM_LDFLAGS)、$(LDFLAGS) :未定义
$(ec_dc_user_example_OBJECTS):ec_dc_user_example-main.o
$(ec_dc_user_example_LDADD) 、$(LIBS):未定义
因此该指令实际为:@echo " CC " $@/bin.bash ../../libtool -silent --mode=link gcc -g -O2 -o @ec_dc_user_example-main.o
小结: 从ec_dc_user_examples: ec_dc_user_example-main.o可知,当前的目标的依赖文件只有main.o,而main.o依赖main.c,但实际上,经过修改的main()调用了在test.c中的test(),因此目标的依赖文件应该为main.o和test.o,因为缺少依赖,所以会出现如图1的错误。
二、Makefile修改
从上面的解析可知,编译失败的原因是缺少依赖文件,因此,只需要在保证头文件路径正确的前提下,在头文件文件夹中加入test.h,并在ec_dc_user_examples: ec_dc_user_example-main.o命令中添加目标的test.o依赖。
上面的目标生成指令中,有ec_dc_user_example_DEPENDENCIES和EXTRA_ec_dc_user_example_DEPENDENCIES两个变量并未使用,因此我选择了EXTRA_ec_dc_user_example_DEPENDENCIES变量作为我的外部文件的依赖定义,如图3
![](https://img-blog.csdnimg.cn/6ecc75d8d96246eaacc88b1d4c1adfc0.png)
对目标文件的指令进行修改,将ec_dc_user_example_DEPENDENCIES和EXTRA_ec_dc_user_example_DEPENDENCIES加入到指令中,修改结果如下
ec_dc_user_example$(EXEEXT): $(ec_dc_user_example_OBJECTS) $(ec_dc_user_example_DEPENDENCIES) $(EXTRA_ec_dc_user_example_DEPENDENCIES)
@rm -f ec_dc_user_example$(EXEEXT)
$(AM_V_CCLD)$(ec_dc_user_example_LINK) $(ec_dc_user_example_OBJECTS) $(ec_dc_user_example_DEPENDENCIES) $(EXTRA_ec_dc_user_example_DEPENDENCIES) $(ec_dc_user_example_LDADD) $(LIBS)
然后再添加对test.o的生成规则,可以仿照已有的进行修改,如下代码
test.o: test.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ec_dc_user_example_CFLAGS) $(CFLAGS) -MT test.o -MD -MP -MF $(DEPDIR)/test.Tpo -c -o test.o `test -f 'main.c' || echo '$(srcdir)/'`test.c
$(AM_V_at)$(am__mv) $(DEPDIR)/test.Tpo $(DEPDIR)/test.Po
其中,生成指令中的ec_dc_user_example_CFLAGS已经指定了头文件目录,在头文件目录中加入test.h头文件,即可编译。
三、编译结果
test()函数功能如下:
#include "test.h"
void test()
{
printf("**********************\n");
printf("yes:%d",1+1);
}
编译结果如图4、图5,生成了ec_dc_user_example、ec_dc_user_example.o、test.o三个文件。
![](https://img-blog.csdnimg.cn/6c0532e5e85c4383b9147fd390787085.png)
![](https://img-blog.csdnimg.cn/f838200ac1244aaa95a1d7d0e0c3a6ae.png)
运行结果如图6,可以看见test()函数已调用并成功打印。
![](https://img-blog.csdnimg.cn/2a309f80a43d4ed1bb4459a53937f5c7.png)
四、Makefile和源文件在不同文件夹内的编译
当我建立了一个src文件夹用来放置.c文件,同时makefile在src的上级目录,此时我需要告诉makefile去哪里找.c文件,需要用到这句指令。
vpath %.c ./src
同时修改规则中的指令,在main.c前增加路径。
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ec_dc_user_example_CFLAGS) $(CFLAGS) -MT ec_dc_user_example-main.o -MD -MP -MF $(DEPDIR)/ec_dc_user_example-main.Tpo -c -o ec_dc_user_example-main.o `test -f 'main.c' || echo '$(srcdir)/'`$(SRCDIR)/main.c
总结
对于如何修改Makefile文件使之可以进行多文件编译,实现模块化编程的关键就在于对目标的生成规则进行完善,并将头文件放置在正确的位置。