后台运行make是否可行?如何在C程序中屏蔽make编译日志?
问题
我想写一个C程序,通过同一个Makefile生成多个不同名称的可执行文件,但每次编译大型程序时,make会输出大量日志(包括-Wall产生的警告、gcc命令执行信息等),多次执行后终端界面杂乱。我有几个疑问:
- 把make放后台运行来隐藏日志可行吗?这是好主意吗?或者后台运行和隐藏日志根本没关系?
- 如果可行,该怎么操作?
我的C程序核心代码如下:
for (int j = 0; tmp2[j] != NULL; j++) { printf("-> %s\n", tmp2[j]); char command[128] = ""; sprintf(command, "make -C %s TARGET=%s all", "file/path/", tmp2[j]); system(command); }
我试过在Linux命令末尾加&后台运行,但日志还是会显示,示例日志如下:
text.c:442:3: warning: blablabla gcc -W -Wall -Wextra -c -g -Os -I. test1.c gcc -W -Wall -Wextra -c -g -Os -I. test2.c gcc -g -o STEM_ECS2_SERVICE_3 main.o json.o config.o debug.o -lnsl -lm -ldl -lc -lmysqlclient -lm /bin/mv *.o ./object
附上团队成员编写的Makefile内容:
include ../../Make.cf OBJ_DIR = ./object CFLAGS = -g -Os $(INCDIR) $(MYSQLINC) -I./include -export-dynamic LDFLAGS = $(SYSNLIB) $(SYSLIB) $(MYSQLLIB) $(THREADLIB) -L$(LIBDIR) \ -lmysqlclient -lm C_OBJECTS = main.o \ json.o \ ecs_config.o \ ecs_debug.o \ ######### define target ######### all: $(TARGET) main.o: main.c $(CC) -W -Wall -Wextra -c $(CFLAGS) $(DEFINES) main.c json.o: json.c $(CC) -W -Wall -Wextra -c $(CFLAGS) $(DEFINES) json.c config.o: config.c $(CC) -W -Wall -Wextra -c $(CFLAGS) $(DEFINES) config.c debug.o: debug.c $(CC) -W -Wall -Wextra -c $(CFLAGS) $(DEFINES) debug.c $(TARGET): $(C_OBJECTS) $(CC) $(CFLAGS) $(DEFINES) -std=gnu99 -o $(TARGET) $(C_OBJECTS) $(LDFLAGS) $(MV) *.o $(OBJ_DIR) touch: $(TOUCH) *.c clean: $(RM) $(OBJ_DIR)/*.o rm -f *.o core $(TARGET) cp: cp -f $(TARGET) $(BINDIR)/$(TARGET)
解决方案
1. 后台运行和隐藏日志的关系
后台运行(加&)只是让进程脱离当前终端的前台控制,但进程的标准输出、标准错误仍会默认指向原终端,因此日志依然会打印出来。也就是说,后台运行本身不能直接隐藏日志,必须结合输出重定向才能实现。
2. 屏蔽make日志的具体方法
方法一:使用make的静默模式+输出重定向
make自带静默参数可以屏蔽自身打印的命令行:
-s/--silent/--quiet:禁止make打印执行的命令,但gcc的警告、错误仍会输出。- 若要彻底屏蔽所有输出(包括警告、错误),需结合输出重定向到空设备。
修改C程序中的命令生成代码:
// 仅屏蔽make打印的命令,保留gcc警告/错误 sprintf(command, "make -s -C %s TARGET=%s all", "file/path/", tmp2[j]); // 彻底屏蔽所有输出(包括警告、错误) sprintf(command, "make -s -C %s TARGET=%s all > /dev/null 2>&1", "file/path/", tmp2[j]);
解释:> /dev/null将标准输出丢弃,2>&1把标准错误(如gcc警告)也重定向到标准输出的位置,最终所有输出都会被丢弃。
方法二:直接重定向所有输出(无需make静默选项)
如果不需要保留任何日志,直接重定向所有输出即可:
sprintf(command, "make -C %s TARGET=%s all > /dev/null 2>&1", "file/path/", tmp2[j]);
这种方式无需依赖make的-s参数,同样能屏蔽所有输出。
方法三:修改Makefile(若允许)
如果可以修改团队的Makefile,给每个命令行加上@前缀,能让make不打印这条命令本身:
main.o: main.c @$(CC) -W -Wall -Wextra -c $(CFLAGS) $(DEFINES) main.c
但这种方法只能屏蔽make打印的命令行,gcc的警告仍会输出。不建议通过修改CFLAGS去掉-Wall/-Wextra来屏蔽警告——这些提示能帮你发现代码潜在问题。
3. 关于后台运行的建议
如果C程序不需要等待make完成再执行下一步,可以结合后台运行和输出重定向,既不阻塞程序,也不会输出日志:
sprintf(command, "make -s -C %s TARGET=%s all > /dev/null 2>&1 &", "file/path/", tmp2[j]);
但要注意:同时后台运行多个make进程会占用更多系统资源,编译大型程序时需根据服务器性能评估是否合适。如果C程序需要按顺序处理每个编译结果,就不要加&,否则会导致逻辑混乱。
内容的提问来源于stack exchange,提问作者dibii

