前些天试着用vscode来编写和编译wxwidgets程序,当程序只有单个源文件时该方法还是可以的。但如果一个工程有多个源文件需要编译后再链接成一个应用程序时,该方法就不哪么方便了。
- 必须单个选中每个源文件后运行编译任务,将源文件编译成.o文件
- 再创建链接任务,将生成的.o文件链接成一个应用程序
所以决定通过Makefile来组织编译工程文件。
wxWidgets.mk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| wxWidgets_root_dir := D:/wxWidgets_3.1.5
wxWidgets_dll_dir_name := gcc810_dll
wxWidgets_dll_compile_type ?= gcc
wxWidgets_debug_libs = $(wildcard $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/*d.a)
wxWidgets_debug_libs += $(wildcard $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/*d_*.a)
wxWidgets_debug_specific_lib = $(wildcard $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/*d_*d.a)
wxWidgets_release_specific_lib = $(subst d_,_, $(wxWidgets_debug_specific_lib))
wxWidgets_debug_libs := $(filter-out $(wxWidgets_debug_specific_lib) $(wxWidgets_release_specific_lib) , $(wxWidgets_debug_libs))
wxWidgets_debug_libs += $(wxWidgets_debug_specific_lib)
wxWidgets_all_libs = $(wildcard $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/*.a)
wxWidgets_release_libs = $(filter-out $(wxWidgets_debug_libs), $(wxWidgets_all_libs))
wxWidgets_link_release_libs = $(subst .a,, $(subst -l.a,lib.a,$(subst lib,-l, $(notdir $(wxWidgets_release_libs)))))
wxWidgets_link_debug_libs = $(subst .a,,$(subst -ld.a,libd.a,$(subst lib,-l, $(notdir $(wxWidgets_debug_libs)))))
wxWidgets_link_lib_paths = $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)
wxWidgets_compile_include_paths = $(wxWidgets_root_dir)/include
ifeq ($(wxWidgets_dll_compile_type),gcc)
ifneq "$(findstring DEBUG, $(CXXFLAGS) $(CPPFLAGS) $(PREDEFINE))" "" wxWidgets_compile_include_paths += $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/mswud else wxWidgets_compile_include_paths += $(wxWidgets_root_dir)/lib/$(wxWidgets_dll_dir_name)/mswu endif else ifeq "$(wxWidgets_dll_compile_type)" "msvc" wxWidgets_compile_include_paths += $(wxWidgets_root_dir)/include/msvc endif
|
该文件中主要定义了wxWidgets的安装目录以及dll库文件夹的名称,根据前面的配置得出:
- 头文件路径
- 链接时引入的库文件名称
Makefile
该文件中设置了5个规则:
规则名 |
作用 |
使用方法 |
build |
编译工程 |
make build |
clean |
清理工程 |
make clean |
rebuild |
重新编译工程 |
make rebuild |
run |
运行应用程序 |
make run |
debug |
调试应用程序 |
make debug |
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
output_file_name = build/HelloWorld.exe
source_files = $(call recursive_search_files, *.cpp *.rc, . src)
include_paths =
lib_paths =
CXX = d:/mingw-64/i686-8.1.0-release-win32-sjlj-rt_v6-rev0/mingw32/bin/g++.exe
RCC = d:/mingw-64/i686-8.1.0-release-win32-sjlj-rt_v6-rev0/mingw32/bin/windres.exe
PREDEFINE = _UNICODE __WX__ _DEBUG
CXXFLAGS = -g -o0 -Wall -pipe -fexec-charset=GBK
LINKOPTIONS = -mwindows
ifneq "$(findstring DEBUG, $(CXXFLAGS) $(CPPFLAGS) $(PREDEFINE))" "" output_file_name := $(basename $(output_file_name))_debug.exe else output_file_name := $(basename $(output_file_name))_release.exe endif
define recursive_search_files = $(foreach path, $(2), \ $(foreach file_pattern,$(1), \ $(wildcard $(path)/$(file_pattern)) \ ) \ ) endef
include wxwidgets.mk
.PHONY: help clean link build rebuild run other
help: @echo " ############ usage ############" @echo "$(MAKE) build build project" @echo '$(MAKE) rebuild rebuild project' @echo "$(MAKE) clean clean project" @echo "$(MAKE) run run application" @echo "$(MAKE) debug debug application"
%.rc.o: @echo '>>>' compile... $(filter %$(basename $(notdir $@)), $(source_files)) @$(RCC) $(addprefix -I,$(wxWidgets_compile_include_paths)) \ -i $(filter %$(basename $(notdir $@)), $(source_files)) \ -o $(dir $(output_file_name))obj/$(notdir $@)
%.o: @echo '>>>' $@ compile... $(filter %$(addsuffix .cpp, $(basename $(notdir $@))), $(source_files))
$(if "$(realpath $(dir $(output_file_name))obj)" "" ,\ @mkdir -p $(dir $(output_file_name))obj,\ ) # 编译.o对应的.cpp文件 @$(CXX) $(CXXFLAGS) $(addprefix -D, $(PREDEFINE)) \ $(addprefix -I,$(wxWidgets_compile_include_paths)) \ -c $(filter %$(addsuffix .cpp, $(basename $(notdir $@))), $(source_files)) \ -o $(dir $(output_file_name))obj/$(notdir $@)
# ifeq "$(build_config)" "debug" # 改用直接在CXXFLAGS、CPPFLAGS中查找是否定义DEBUG变量来判断是debug版还是release ifneq "$(findstring DEBUG, $(CXXFLAGS) $(CPPFLAGS) $(PREDEFINE))" "" wxwidgets_libs = $(wxWidgets_link_debug_libs) else wxwidgets_libs = $(wxWidgets_link_release_libs) endif
# 链接.o文件生成应用程序 build: $(patsubst %.rc,%.rc.o, $(addprefix $(dir $(output_file_name))obj/, $(notdir $(source_files:.cpp=.o)))) @echo '>>>' link... $(output_file_name) # 将依赖关系中的所有.o文件链接成应用程序 @$(CXX) -o $(output_file_name) $^ \ $(addprefix -L,$(wxWidgets_link_lib_paths) $(lib_paths)) \ $(wxwidgets_libs) \ $(LINKOPTIONS)
clean: @-rm -rfv $(dir $(output_file_name))
rebuild: clean build
run: # shell脚本判断目标文件是否存在,若不存在先调用 make build生成应用 @if [ -a $(output_file_name) ];then \ start $(output_file_name); \ else \ $(MAKE) build; \ start $(output_file_name); \ fi
debug: # shell脚本判断目标文件是否存在,若不存在先调用 make build生成应用程序 @if [ ! -f $(output_file_name) ]; \ then \ $(MAKE) build ; \ fi; \ gdb $(output_file_name); \
other: @echo '>>>>>>>>>>>>>>>>>>>>>>>>>>>'
|
make build
- 在
output_file_name
目录下创建一个obj子目录
- 将
source_files
中的所有.cpp文件和.rc文件全都编译生.o文件并存放在obj目录下
- 将obj下的所有.o文件链接成一个应用程序
make clean
- 删除所有.o文件和应用程序
make rebuild
- 先删除所有.o文件和应用程序
- 重新构建应用程序
make run
- 判断应用程序是否存在,若不存在先构建应用程序
- 若存在启动应用程序
make debug
- 判断应用程序是否存在,若不存在先构建应用程序
- 若存在调用gdb调试应用程序
以上Makefile存在的问题
- 在使用
make rebuild -j4
可能会报目录不存在的错
- 当某个源文件发生更新时,若.o文件若在
make build
只会重新链接不会编译
对上面两个文件的改进
对文件做了如下改进:
- 增加了
wxWidgets_root_path
和wxWidgets_dll_path
目录的末尾/
的处理。
以满足设置目录时可以带/
也可以不带
- 增加了对以上两个目录正确性的判断处理,如果设置的目录路径错误。提示错误信息
wxWidgets.mk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| wxWidgets_root_path ?= D:/wxWidgets_3.1.5
wxWidgets_dll_path ?= $(wxWidgets_root_path)/lib/gcc810_dll
wxWidgets_root_path := $(patsubst %/,%,$(wxWidgets_root_path)) wxWidgets_dll_path := $(patsubst %/,%,$(wxWidgets_dll_path))
check_dir_is_exsit = $(shell if [ -d $(1) ];then echo $(1);fi)
ifeq "$(call check_dir_is_exsit, $(wxWidgets_root_path))" "" $(error $(wxWidgets_root_path) is not exsit ! Please reconfigure wxWidgets_root_dir) endif
ifeq "$(call check_dir_is_exsit, $(wxWidgets_dll_path))" "" $(error $(wxWidgets_dll_path) is not exsit ! Please reconfigure wxWidgets_dll_dir) endif
wxWidgets_dll_compile_type ?= gcc
wxWidgets_debug_libs = $(wildcard $(wxWidgets_dll_path)/*d.a)
wxWidgets_debug_libs += $(wildcard $(wxWidgets_dll_path)/*d_*.a)
wxWidgets_debug_specific_lib = $(wildcard $(wxWidgets_dll_path)/*d_*d.a)
wxWidgets_release_specific_lib = $(subst d_,_, $(wxWidgets_debug_specific_lib))
wxWidgets_debug_libs := $(filter-out $(wxWidgets_debug_specific_lib) $(wxWidgets_release_specific_lib) , $(wxWidgets_debug_libs))
wxWidgets_debug_libs += $(wxWidgets_debug_specific_lib)
wxWidgets_all_libs = $(wildcard $(wxWidgets_dll_path)/*.a)
wxWidgets_release_libs = $(filter-out $(wxWidgets_debug_libs), $(wxWidgets_all_libs))
wxWidgets_link_release_libs = $(subst .a,, $(subst -l.a,lib.a,$(subst lib,-l, $(notdir $(wxWidgets_release_libs)))))
wxWidgets_link_debug_libs = $(subst .a,,$(subst -ld.a,libd.a,$(subst lib,-l, $(notdir $(wxWidgets_debug_libs)))))
wxWidgets_link_lib_paths = $(wxWidgets_dll_path)
wxWidgets_compile_include_paths = $(wxWidgets_root_path)/include
ifneq "$(findstring DEBUG, $(CXXFLAGS) $(CPPFLAGS) $(PREDEFINE))" "" wxWidgets_compile_include_paths += $(wxWidgets_dll_path)/mswud wxWidgets_link_libs = $(wxWidgets_link_debug_libs) else wxWidgets_compile_include_paths += $(wxWidgets_dll_path)/mswu wxWidgets_link_libs = $(wxWidgets_link_release_libs) endif
|
Makefile
对文件做了如下改进:
- 重构了
build
目标,修复原来源文件改变时,因为.o文件未更新而导致目标应用程序不更新的Bug.
- 重构了
rebuild
目录,修复了原来的make rebuild -j8
出错的问题.
- 重构了
run
目录,修复当再次编译出错,目标应用程序未生成时仍启动应用程序的bug.
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| output_file_name = build/HelloWorld.exe
source_files = $(call pattern_recursive_files, *.cpp *.rc, ./ ./src/)
include_paths = ./ ./src
lib_paths =
CXX = d:/mingw-64/i686-8.1.0-release-win32-sjlj-rt_v6-rev0/mingw32/bin/g++.exe
RCC = d:/mingw-64/i686-8.1.0-release-win32-sjlj-rt_v6-rev0/mingw32/bin/windres.exe
PREDEFINE = _UNICODE __WX__ _DEBUG
CXXFLAGS = -g -o0 -Wall -pipe -fexec-charset=GBK
LINKOPTIONS = -mwindows
define pattern_recursive_files $(foreach path, $(2), \ $(foreach file_pattern,$(1), \ $(wildcard $(patsubst %/,%,$(path))/$(file_pattern)) \ ) \ ) endef
ifneq "$(findstring DEBUG, $(CXXFLAGS) $(CPPFLAGS) $(PREDEFINE))" "" output_file_name := $(join $(basename $(output_file_name)), _debug.exe) else output_file_name := $(join $(basename $(output_file_name)), _release.exe) endif
include wxWidgets.mk
.PHONY: help build clean rebuild debug
help: @echo " ############ usage ############" @echo "$(MAKE) build build project" @echo '$(MAKE) rebuild rebuild project' @echo "$(MAKE) clean clean project" @echo "$(MAKE) run run application" @echo "$(MAKE) debug debug application"
build: $(output_file_name)
%.rc.o: @echo compile... $(filter %$(basename $(notdir $@)), $(source_files)) '->' $@
@if [ ! -d $(dir $@) ];then \ echo "mkdir -p $(dir $@)"; \ mkdir -p $(dir $@);\ fi
@$(RCC) $(addprefix -I,$(wxWidgets_compile_include_paths)) \ -i $(filter %$(basename $(notdir $@)), $(source_files)) \ -o $@
%.cpp.o: $(filter %.cpp, $(source_files)) $(call pattern_recursive_files, *.h, $(include_paths)) @echo compile... $(filter %$(basename $(notdir $@)), $^) '->' $@
@if [ ! -d $(dir $@) ];then \ echo "mkdir -p $(dir $@)"; \ mkdir -p $(dir $@);\ fi
@$(CXX) $(CXXFLAGS) $(addprefix -D, $(PREDEFINE)) \ $(addprefix -I,$(wxWidgets_compile_include_paths)) \ -c $(filter %$(basename $(notdir $@)), $^) \ -o $@
$(output_file_name): $(addprefix $(join $(dir $(output_file_name)), obj/), $(addsuffix .o, $(notdir $(source_files)))) @echo link... $^ '->' $@ @$(CXX) -o $@ $^ \ $(addprefix -L,$(wxWidgets_link_lib_paths) $(lib_paths)) \ $(wxWidgets_link_libs) \ $(LINKOPTIONS)
clean: @-rm -rfv $(dir $(output_file_name))
rebuild: @$(MAKE) --no-print-directory clean @$(MAKE) --no-print-directory build
run:
@if [ ! -f $(output_file_name) ];then \ $(MAKE) --no-print-directory build; \ fi; \ [ $? ] && start $(output_file_name)
debug:
@if [ ! -f $(output_file_name) ]; \ then \ $(MAKE) build ; \ fi; \ [ $? ] && gdb $(output_file_name); \
test: @echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" @echo wxWidgets_debug_libs '->' $(words $(wxWidgets_debug_libs)) @echo wxWidgets_release_libs '->' $(words $(wxWidgets_release_libs)) @echo $(wxWidgets_link_libs) @echo "---------------------------------------" @echo $(addprefix $(join $(dir $(output_file_name)), obj/), $(addsuffix .o, $(notdir $(source_files))))
|
注意事项
在家中电脑运行make run
和make debug
时能正常启动应用程序,但在公司电脑却无法启动和调试应用。可能是因为公司电脑Msys2中也安装了mingw32的原因。最后重装msys2就正常了!