创建 linux make/build 文件

发布于 2024-09-16 06:45:34 字数 1498 浏览 5 评论 0 原文

我正在将一个 C++ 项目从 Windows 迁移到 Linux,现在需要创建一个构建/make 文件。我以前从未创建过构建/生成文件。我还需要包含 Boost 库以使其更加复杂。 它也必须是一个 makefile,无论如何我都需要学习如何创建 makefile,所以 CMake 和 SCON 已经淘汰了。由于使用了 Boost,IDE 也被淘汰了,我所有的 IDE(Eclipse、VS 等)都只能在 Windows 上运行。我必须从头开始生成一个 makefile。

那么创建 Linux c++ make 文件的基础知识是什么以及如何将 Boost 库合并到其中以使其正确链接?

到目前为止,我的 makefile 看起来像这样。我认为 CFLAGS 和 LDFLAGS 是编译器和优化选项,但不完全确定。

CC = g++
CFLAGS = -wall -o3 - c
LDFLAGS = -03 -mfp-rounding-mode=n

我提供赏金,因为我仍然很迷失。如果有人喜欢冒险,我需要在 linux

  • simple_ls.h
  • simple_ls.cpp
  • 2dquicksort.h
  • rawr.h
  • rawr.cpp
  • converter.cpp

中编译以下内容 simple_ls.h 中的标头:

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/lexical_cast.hpp"

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

2dquicksort.h 中的标头: 2dquicksort.h

#include <stdio.h>
#include <ctype.h>
#include <iostream>

中的标头 : rawr.h:

#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // or (stdlib.h) for exit()

#include <cmath> 
#include <vector>
#include <limits>
#include <string>

一个可接受的答案是逐步解释 makefile 如何工作以及如何在没有 IDE 的 Linux 中使用 Boost 构建它们。

I am moving a C++ project from Windows to Linux and I now need to create a build/make file. I have never created a build/make file before. I also need to include Boost libraries to make it more complicated. It must also be a makefile and I need to learn how to create makefile anyway, so CMake and SCON are out. IDEs are also out because of the use of Boost and all my IDEs (Eclipse, VS, etc.) are only on windows. I must generate a makefile from scratch.

So what are the basics of creating a Linux c++ make file and how to incorporate the Boost libraries in it to have it properly link?

So far, my makefile looks like this. I think CFLAGS and LDFLAGS are compiler and optimization options, but not totally sure.

CC = g++
CFLAGS = -wall -o3 - c
LDFLAGS = -03 -mfp-rounding-mode=n

I am offering a bounty because I am still very lost. In case anyone is feeling adventurous, I need to compile the following in linux

  • simple_ls.h
  • simple_ls.cpp
  • 2dquicksort.h
  • rawr.h
  • rawr.cpp
  • converter.cpp

The headers in simple_ls.h:

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/lexical_cast.hpp"

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

The headers in 2dquicksort.h:

#include <stdio.h>
#include <ctype.h>
#include <iostream>

The headers in rawr.h:

#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // or (stdlib.h) for exit()

#include <cmath> 
#include <vector>
#include <limits>
#include <string>

An acceptable answer would be a step-by-step explanation of how makefiles work and how to build them with Boost in Linux without an IDE.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

心清如水 2024-09-23 06:45:34

什么是Makefile(应用于 Boost 项目)

递归 Makefile 背后的想法是:

要构建目标,我们需要先决条件(其他目标!)和构建说明

先决条件

它们是文件、文件夹或假目标(通常在.PHONY)。测试文件/文件夹的存在性和修改日期。

如果目标没有先决条件或者比任何先决条件都旧,则需要重建目标。

指令

指令是shell 命令,从一个选项卡开始。每条指令行都是一个 shell 实例。当当前命令以反斜杠 \ 结尾时,shell 命令可以在下一行继续。

目标定义

目标可以是依赖项,也可以是规则

依赖性:

target : prerequisite1 prerequisite2 prerequisiteN

规则:

target : prerequisite1 prerequisite2 prerequisiteN
    instructions1
    @hidden_batch1 ; \
  hidden_batch2  

指令开始前有制表符。

调试

Makefile 的调试可能会变得非常令人头疼。
请尝试在 Makefile 中执行以下操作来显示跟踪(包含警告的文件和行位置):

$(info Shell: $(SHELL))
$(warning CXX: $(CXX))

当您的 Makefile 包含大量嵌套的 if/else/endif 并且您不确定
现在的路径是什么?

Makefile 结构

理想的 makefile 结构是:

  1. 变量设置
  2. 目标/依赖项声明

一旦整个 Makefile 及其包含文件完成,真正的目标指令处理就会开始
已被理解(存储在 make 内部数据库中)。

示例

最后,使用 Boost 将理论应用到这个特定示例并创建假源文件
来说明。

rawr.cpp

#include "rawr.h"

simple_ls.cpp

#include "rawr.h"

converter.cpp

#include <iostream>

#include "rawr.h"
#include "simple_ls.h"
#include "2dquicksort.h"

#include <boost/array.hpp>   // Boost! 

int main(int argc, char **argv)
{
    boost::array<int,4> a = { { 1, 2, 3, 4} };
    std::cout << a[1] << std::endl;
    return 0;
}

Makefile

如果您从 *stack***overflow** 复制 Makefile 源,请不要忘记用真正的制表符替换空格:

sed -i~ -e 's/^    /\t/' Makefile

Makefile 源:

## Makefile for C++ project using Boost
#
# @author Cedric "levif" Le Dillau
#
# Some notes:
# - Using ':=' instead of '=' assign the value at Makefile parsing time,
#   others are evaluated at usage time. This discards
# - Use ':set list' in Vi/Vim to show tabs (Ctrl-v-i force tab insertion)
#

# List to '.PHONY' all fake targets, those that are neither files nor folders.
# "all" and "clean" are good candidates.
.PHONY: all, clean

# Define the final program name
PROGNAME := converter

# Pre-processor flags to be used for includes (-I) and defines (-D) 
CPPFLAGS := -DUSE_BOOST

# CFLAGS is used for C compilation options.
CFLAGS := -Wall -O0

# CXXFLAGS is used for C++ compilation options.
CXXFLAGS += -Wall -O0

# LDFLAGS is used for linker (-g enables debug symbols)
LDFLAGS  += -g

# Which Boost modules to use (all)
BOOST_MODULES = \
  date_time     \
  filesystem    \
  graph         \
  iostreams     \
  math_c99      \
  system        \
  serialization \
  regex

# Boost libraries' type (a suffix)
BOOST_MODULES_TYPE := -mt

# Define library names with their type
BOOST_MODULES_LIBS := $(addsuffix $(BOOT_MODULES_TYPE),$(BOOST_MODULES))

# Define the linker argument to use the Boost libraries.
BOOST_LDFLAGS := $(addprefix -lboost_,$(BOOST_MODULES_LIBS))

# Feed compiler/linker flags with Boost's
CPPFLAGS += $(BOOST_CPPFLAGS)
LDFLAGS += $(BOOST_LDFLAGS)

# List the project' sources to compile or let the Makefile recognize
# them for you using 'wildcard' function.
#
#SOURCES = simple_ls.cpp rawr.cpp converter.cpp
SOURCES = $(wildcard *.cpp)

# List the project' headers or let the Makefile recognize
# them for you using 'wildcard' function.
#
#HEADERS = simple_ls.h 2dquicksort.h rawr.h
HEADERS = $(wildcard %.h)

# Construct the list of object files based on source files using
# simple extension substitution.
OBJECTS = $(SOURCES:%.cpp=%.o)

#
# Now declare the dependencies rules and targets
#
# Starting with 'all' make it  becomes the default target when none 
# is specified on 'make' command line.
all : $(PROGNAME)

# Declare that the final program depends on all objects and the Makfile
$(PROGNAME) : $(OBJECTS) Makefile
    $(CXX) -o $@ $(LDFLAGS) $(OBJECTS)

# Now the choice of using implicit rules or not (my choice)...
#
# Choice 1: use implicit rules and then we only need to add some dependencies
#           to each object.
#
## Tells make that each object file depends on all headers and this Makefile.
#$(OBJECTS) : $(HEADERS) Makefile
#
# Choice 2: don't use implicit rules and specify our will
%.o: %.cpp $(HEADERS) Makefile
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) 
lt;

# Simple clean-up target
# notes:
# - the '@' before 'echo' informs make to hide command invocation.
# - the '-' before 'rm' command to informs make to ignore errors.
clean :
    @echo "Clean."
    -rm -f *.o $(PROGNAME)

文件列表

2dquicksort.h
converter.cpp
Makefile
rawr.cpp
rawr.h
simple_ls.cpp
simple_ls.h

编译

make clean all
Clean.
rm -f *.o converter
g++ -Wall -O0 -DUSE_BOOST  -c -o converter.o converter.cpp
g++ -Wall -O0 -DUSE_BOOST  -c -o rawr.o rawr.cpp
g++ -Wall -O0 -DUSE_BOOST  -c -o simple_ls.o simple_ls.cpp
g++ -o converter -g -lboost_date_time -lboost_filesystem -lboost_graph -lboost_iostreams -lboost_math_c99 -lboost_system -lboost_serialization -lboost_regex converter.o rawr.o simple_ls.o

结果

和现在,几乎最小的 Boost 程序的结果:

./converter
2

没有理由不使用它! Boost 确实是一个特色 C++ 工具箱:)

What is a Makefile ? (applied to a Boost project)

The root recursive idea behind Makefile is:

To build a target we need prerequisites (other targets!) and instructions to build

Prerequisites

They are either files, folders or fake targets (usually in .PHONY). Files/folders are tested for existence and modification date.

The target needs to be rebuilt if it has no prerequisite or if older that any of the prerequisites.

Instruction

An Instruction is shell commands, starting with one tab. Each instruction line is one shell instance. The shell command can be continued on next line when the current one ends with backslash \.

Target definition

A target is either a dependency or a rule.

Dependency:

target : prerequisite1 prerequisite2 prerequisiteN

Rule:

target : prerequisite1 prerequisite2 prerequisiteN
    instructions1
    @hidden_batch1 ; \
  hidden_batch2  

With tabs in front of instruction start.

Debug

Debugging a Makefile can become a real headache.
Try the following in your Makefile to show traces (with file and line location for warning):

$(info Shell: $(SHELL))
$(warning CXX: $(CXX))

This is helpful when your Makefile contains lots of nested if/else/endif and you're not sure
anymore what is the current path.

Makefile Structure

The ideal makefile structure is:

  1. variable setup
  2. target/dependency declarations

The real target-instructions processing starts once the whole Makefile and its include files
has been understood (stored in make internal database).

Example

Finally, apply theory to this specific example using Boost and create fake source files
to illustrate.

rawr.cpp

#include "rawr.h"

simple_ls.cpp

#include "rawr.h"

converter.cpp

#include <iostream>

#include "rawr.h"
#include "simple_ls.h"
#include "2dquicksort.h"

#include <boost/array.hpp>   // Boost! 

int main(int argc, char **argv)
{
    boost::array<int,4> a = { { 1, 2, 3, 4} };
    std::cout << a[1] << std::endl;
    return 0;
}

Makefile

Don't forget to replace spaces with real Tabs if you copy Makefile source from *stack***overflow** :

sed -i~ -e 's/^    /\t/' Makefile

Makefile source:

## Makefile for C++ project using Boost
#
# @author Cedric "levif" Le Dillau
#
# Some notes:
# - Using ':=' instead of '=' assign the value at Makefile parsing time,
#   others are evaluated at usage time. This discards
# - Use ':set list' in Vi/Vim to show tabs (Ctrl-v-i force tab insertion)
#

# List to '.PHONY' all fake targets, those that are neither files nor folders.
# "all" and "clean" are good candidates.
.PHONY: all, clean

# Define the final program name
PROGNAME := converter

# Pre-processor flags to be used for includes (-I) and defines (-D) 
CPPFLAGS := -DUSE_BOOST

# CFLAGS is used for C compilation options.
CFLAGS := -Wall -O0

# CXXFLAGS is used for C++ compilation options.
CXXFLAGS += -Wall -O0

# LDFLAGS is used for linker (-g enables debug symbols)
LDFLAGS  += -g

# Which Boost modules to use (all)
BOOST_MODULES = \
  date_time     \
  filesystem    \
  graph         \
  iostreams     \
  math_c99      \
  system        \
  serialization \
  regex

# Boost libraries' type (a suffix)
BOOST_MODULES_TYPE := -mt

# Define library names with their type
BOOST_MODULES_LIBS := $(addsuffix $(BOOT_MODULES_TYPE),$(BOOST_MODULES))

# Define the linker argument to use the Boost libraries.
BOOST_LDFLAGS := $(addprefix -lboost_,$(BOOST_MODULES_LIBS))

# Feed compiler/linker flags with Boost's
CPPFLAGS += $(BOOST_CPPFLAGS)
LDFLAGS += $(BOOST_LDFLAGS)

# List the project' sources to compile or let the Makefile recognize
# them for you using 'wildcard' function.
#
#SOURCES = simple_ls.cpp rawr.cpp converter.cpp
SOURCES = $(wildcard *.cpp)

# List the project' headers or let the Makefile recognize
# them for you using 'wildcard' function.
#
#HEADERS = simple_ls.h 2dquicksort.h rawr.h
HEADERS = $(wildcard %.h)

# Construct the list of object files based on source files using
# simple extension substitution.
OBJECTS = $(SOURCES:%.cpp=%.o)

#
# Now declare the dependencies rules and targets
#
# Starting with 'all' make it  becomes the default target when none 
# is specified on 'make' command line.
all : $(PROGNAME)

# Declare that the final program depends on all objects and the Makfile
$(PROGNAME) : $(OBJECTS) Makefile
    $(CXX) -o $@ $(LDFLAGS) $(OBJECTS)

# Now the choice of using implicit rules or not (my choice)...
#
# Choice 1: use implicit rules and then we only need to add some dependencies
#           to each object.
#
## Tells make that each object file depends on all headers and this Makefile.
#$(OBJECTS) : $(HEADERS) Makefile
#
# Choice 2: don't use implicit rules and specify our will
%.o: %.cpp $(HEADERS) Makefile
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) 
lt;

# Simple clean-up target
# notes:
# - the '@' before 'echo' informs make to hide command invocation.
# - the '-' before 'rm' command to informs make to ignore errors.
clean :
    @echo "Clean."
    -rm -f *.o $(PROGNAME)

File list

2dquicksort.h
converter.cpp
Makefile
rawr.cpp
rawr.h
simple_ls.cpp
simple_ls.h

Compilation

make clean all
Clean.
rm -f *.o converter
g++ -Wall -O0 -DUSE_BOOST  -c -o converter.o converter.cpp
g++ -Wall -O0 -DUSE_BOOST  -c -o rawr.o rawr.cpp
g++ -Wall -O0 -DUSE_BOOST  -c -o simple_ls.o simple_ls.cpp
g++ -o converter -g -lboost_date_time -lboost_filesystem -lboost_graph -lboost_iostreams -lboost_math_c99 -lboost_system -lboost_serialization -lboost_regex converter.o rawr.o simple_ls.o

Result

And now, the result of nearly the tiniest Boost program:

./converter
2

No excuse not to use it ! Boost is really a featured C++ toolbox :)

好听的两个字的网名 2024-09-23 06:45:34

一个非常简单的 GNU makefile 如下:

CPPFLAGS += -Isome_include_path
CXXFLAGS += -O3
LDFLAGS  += -Lsome_link_path -lsome_lib -lboost_filesystem

all: binary_name
binary_name: foo.o bar.o john.o
  • CPPFLAGS 是应用于 C 预处理器的标志。诸如包含路径之类的东西。
  • CXXFLAGS 是应用于 C++ 编译器的标志。诸如优化级别之类的事情。
  • LDFLAGS 是应用于链接器的标志。诸如外部库(boost_filesystem)和其他库之类的东西。另外,还有这些库的路径。
  • 惯例表明应该有一个 make all 规则,这是默认规则。在 make 中,第一条规则是默认的。
  • binary_name 是二进制文件的名称。
  • binary_name 取决于 3 个文件:foo.obar.ojohn.o
  • 我们不包含 *.o 的规则,因为 gnu make 对这些规则有隐式规则。

要使用 make,您需要创建一个名为 Makefile 的文件,其中包含上面列出的内容。要构建,您需要在该目录中运行 make

顺便说一句(正如其他人提到的),我建议如果可能的话,不要使用 make。那里有更好的系统。 make 的主要好处是它无处不在。然而,如果管理层需要它,那么管理层就需要它。

(请注意,GNU Make += 表示法并不总是可移植到其他版本的 Make。但是,Linux 上的 make 是 GNU Make。)


根据您的编辑,这里有一个示例与您记下的文件。需要注意的是,以 $(CXX) 开头的行应该以 TAB 字符开头!

LDFLAGS  := -lboost_filesystem
CXXFLAGS := -O3 -Wall
CPPFLAGS :=

all: program
program: simple_ls.o converter.o rawr.o
    $(CXX) -o 
lt; $^ $(LDFLAGS)

simple_ls.o: simple_ls.cpp rawr.h simple_ls.h 2dquicksort.h
converter.o: converter.cpp rawr.h simple_ls.h 2dquicksort.h
rawr.o: rawr.cpp rawr.h simple_ls.h 2dquicksort.h

A very simple GNU makefile follows:

CPPFLAGS += -Isome_include_path
CXXFLAGS += -O3
LDFLAGS  += -Lsome_link_path -lsome_lib -lboost_filesystem

all: binary_name
binary_name: foo.o bar.o john.o
  • CPPFLAGS are flags that are applied to the C Preprocessor. Things like include paths.
  • CXXFLAGS are flags that are applied to the C++ compiler. Things like optimization levels.
  • LDFLAGS are flags that applied to the linker. Things like external libraries (boost_filesystem) and other libraries. Also, the paths to those libraries.
  • Convention says that there should be a make all rule, which is the default. In make, the first rule is the default.
  • binary_name is the name of your binary.
  • binary_name depends on 3 files: foo.o, bar.o, john.o.
  • We don't include rules for *.o because gnu make has an implicit rule for those.

To use make, you would create a file named Makefile with the contents listed above. To build, you would run make in that directory.

As an aside (and as others have mentioned), I would recommend moving away from make if possible. There are better systems out there. The main benefit of make is that it's everywhere. However, if management requires it, then management requires it.

(Note that the GNU Make += notation is not always portable to other versions of Make. However, make on Linux is GNU Make.)


Given your edit, here's an example with the files that you note. The one caution is that the line beginning with $(CXX) should begin with a TAB character!

LDFLAGS  := -lboost_filesystem
CXXFLAGS := -O3 -Wall
CPPFLAGS :=

all: program
program: simple_ls.o converter.o rawr.o
    $(CXX) -o 
lt; $^ $(LDFLAGS)

simple_ls.o: simple_ls.cpp rawr.h simple_ls.h 2dquicksort.h
converter.o: converter.cpp rawr.h simple_ls.h 2dquicksort.h
rawr.o: rawr.cpp rawr.h simple_ls.h 2dquicksort.h
素手挽清风 2024-09-23 06:45:34

我不建议编写您自己的 Makefile。相反,请使用 CMakeSCons.

值得注意的是,这些工具是跨平台的。因此您可以在 Linux 和 Windows 上使用相同的构建系统。

I would not recommend writing your own Makefiles. Instead, use a build system like CMake or SCons.

It is worth noting that those tools are cross-platform. So you can use the same build system on Linux and Windows.

锦欢 2024-09-23 06:45:34

当然,您应该阅读 The Fine Manual(特别是 gcc 和 make)。不过,以下是 gcc 的基础知识:

编译源文件:

g++ -c file.cpp

这将创建 file.o。然后您可能想要链接它们:

g++ -o app_name file.o main.o other_file.o

这将创建一个名为app_name的可执行文件。但由于您使用的是 boost 并且头文件可能遍布各处,因此您可能需要其他选项。在编译期间使用 -I 将目录添加到包含路径:

g++ -I/usr/local/more_includes/ -c file.cpp

您可能还需要链接到一些库。链接期间:

g++ -L/usr/local/more_libraries/ file.o main.o other_file.o -lsome_library

现在进入 makefile。 makefile 的基础知识是:

target: dependencies
    command

例如:

my_app: file.o
    g++ -o my_app file.o

file.o: file.cpp file.h
    g++ -o file.cpp

clean:
    rm file.o my_app

如果您键入“make”,它将默认尝试创建第一个目标。 my_app 依赖于目标 file.o,因此它将检查自上次修改 my_app 以来 file.o 是否已被修改。如果是这样,它将重新链接。在检查 file.o 时,它注意到 file.o 依赖于 file.cpp 和 file.h。如果自上次创建 file.o 以来这些文件中的任何一个已被修改,它将重新编译该文件。

目标也不必总是实际文件。最后一个称为 clean,它不依赖任何东西,只是删除 file.o 和 my_app。如果您输入“make clean”,它将运行该命令。

当然还有很多其他选择,但这应该可以帮助您入门。

Of course you should Read The Fine Manual (specifically gcc and make). However, here are the basics for gcc:

To compile a source file:

g++ -c file.cpp

This will create file.o. Then you'll probably want to link them:

g++ -o app_name file.o main.o other_file.o

This will create an executable called app_name. But since you are using boost and might have header files located all over the place, you'll probably need additional options. Use -I during the compilation to add a directory to the include path:

g++ -I/usr/local/more_includes/ -c file.cpp

You'll probably also need to link to some libraries. During linking:

g++ -L/usr/local/more_libraries/ file.o main.o other_file.o -lsome_library

Now onto makefiles. The basics of a makefile are:

target: dependencies
    command

For example:

my_app: file.o
    g++ -o my_app file.o

file.o: file.cpp file.h
    g++ -o file.cpp

clean:
    rm file.o my_app

If you type 'make' it will be default try to create the first target. my_app depends on the target file.o, so it will check to see if file.o has been modified since the last time my_app has been modified. If so, it will relink. In checking file.o, it notices that file.o depends on file.cpp and file.h. If either of those files have been modified since the last time file.o was created, it will recompile that file.

Targets don't always have to be actual files either. The last one is called clean, it doesn't depend on anything and just deletes file.o and my_app. If you type 'make clean' it will run the command.

There are of course a ton of other options, but that should get you started.

櫻之舞 2024-09-23 06:45:34

至少尝试阅读您要使用的产品的官方文档: 这里。它确实解释了几乎所有的基础知识。

特别是,阅读第 2 章和第 3 章,这些将使您 99% 达到有效使用 gmake 所需的程度。此外,请仔细阅读 隐式规则目录。这将告诉您大多数“特殊变量”是什么。

我给您的一个提示是在您的项目目录中尝试 gcc -M *.cpp 。这将以 Makefile 格式输出每个 .cpp 文件的先决条件标头列表。事实上,对于初学者 makefile,您可以这样做:

gcc -M *.cpp > Makefile

编辑此文件,或多或少地在前面添加 shath 的答案,然后您就拥有了一个可用的 Makefile。我可能会建议您删除 gcc -M 将添加到每个构建规则中的大量系统标头,但您实际上不必这样做。

FWIW,如果您开始处理一个大型项目(多个源目录是一个很好的线索),那么是时候开发一种现代构建管理工具(这里是 cmake 粉丝)。但对于小型项目来说,raw make 非常容易使用。

At least try to read through the official documentation of the product you're trying to use: here. It does explain nearly all of the basics.

In particular, read chapters 2 and 3, those will get you 99% of the way to where you need to be to use gmake effectively. In addition, carefully read the Catalogue of Implicit Rules. This will tell you what most of those "special variables" are.

One hint I'd give you is to try out gcc -M *.cpp in your project directory. This will output a list of prerequisite headers for each of your .cpp files in Makefile format. In fact, for a starter makefile, you can just do:

gcc -M *.cpp > Makefile

Edit this file, more or less prepending sharth's answer to it, and you have a workable Makefile. I would probably advise you remove the large number of system headers that gcc -M is going to add to each build rule, but you don't really have to.

FWIW, if you start working on a large project (more than one source directory is a good clue), it's time to break out a modern build management tool (cmake fan here). But for small projects, raw make is pretty easy to use.

似狗非友 2024-09-23 06:45:34

这并不完全是您所要求的,但我强烈建议您使用名为 premake 的构建系统。 premake 和 scons 以及 cmake 之间的好处和区别是它为您生成 makefile。这意味着您可以使用 premake 作为开始,然后查看它生成的文件以了解更多信息。

除了这个预制件之外,它还是一个易于学习且直观的工具,它还有一个额外的好处,即能够从相同的配置生成 Visual Studio 项目文件。

我的建议是,如果您绝对需要 makefile,则使用 premake,它将帮助您学习,并最终成为直接编写自己的 makefile 的灵活替代品(这是一个主要的痛苦是 %*$)。

It's not exactly what you were requesting but I would highly recommend that you use a build system called premake. The benefit, and difference, between premake and scons and cmake is that it generates makefiles for you. This means that you can use premake as a start and then look at the files it generates to learn more.

Aside from this premake is an easy to learn and intuitive tool and it has the added benefit of being able to generate visual studio project files from the same configuration.

My advice would be to use premake if you absolutely have to have makefiles, it will help you learn and is ultimately a flexible replacement for directly writing your own makefiles (which is a major pain is the %*$).

酒与心事 2024-09-23 06:45:34

有一个非常好的教程@ ALP

There is a very good tutorial @ ALP.

蓝海 2024-09-23 06:45:34

首先,我不是 Makefile 方面的专家。我知道基础知识,但是这个答案中的 Makefile 几乎肯定有改进的空间。有很多技巧和快捷方式可以让您比硬编码所有内容更好地处理依赖项和添加文件。不过,我认为这个例子足以满足您的目的,并且可能更具教育意义。

其次,我想确保您了解构建项目的基本阶段。您可能已经知道这一点,但如果您不知道,下面的内容一开始会有点混乱。本质上有两个步骤:编译和链接。编译会将您的代码转换为目标代码 - 如果成功,它将把 .cpp 文件转换为 .o 文件。下一步是链接。在这里,它将所有目标代码粘在一起以创建可执行文件,并将函数调用从一个文件链接到另一个文件(因此,如果 file1.cpp 调用 file2.cpp 中定义的函数,则在这一步file1.cpp 找出该函数的实际位置)。还有更多内容,但这应该足以阐明以下内容。

此时,您可以使用 g++ 来编译和链接您的项目(您甚至可以“一步”完成)。然而,这是相当麻烦的,尤其是对于任何重要的项目。它还使得跟踪自上次编译以来已更改的文件变得困难。

这就是 Makefile 的用武之地。 Makefile 是以下形式的规则列表:(

target: dependencies
    command

确保使用制表符而不是空格,如果使用空格,make 可能无法工作)。如果运行命令:

make some_target

那么 make 将查找带有 some_target 的规则。如果目标是一个文件,它将检查该文件的“上次修改”时间戳,并将检查您列出的所有依赖项的时间戳。如果任何依赖项具有较晚的时间戳,它将运行该命令。

我将不得不对您的项目做出一些假设(即哪些文件依赖于哪些文件),因此您可能需要修改以下内容,但这是您项目的基本 Makefile(请记住,制表符而不是空格。如果您复制并粘贴此内容,它将不起作用):

CC = g++
INCLUDE_DIRS = -I/path/to/boost

all: binary_file

clean:
    rm *.o
    rm binary_file

binary_file: simple_ls.o rawr.o converter.o
    $(CC) -o binary_file simple_ls.o rawr.o converter.o

rawr.o: rawr.h rawr.cpp 2dquicksort.h
    $(CC) -c rawr.cpp $(INCLUDE_DIRS)

simple_ls.o: simple_ls.h simple_ls.cpp 2dquicksort.h
    $(CC) -c simple_ls.cpp $(INC*emphasized text*LUDE_DIRS)

运行 makemake allmake binary_file 将导致编译所有文件如有必要,然后链接以创建名为 binary_file 的可执行文件。您可以进行一些改进,例如:

%.o: %.cpp %.h 2dquicksort.h
    $(CC) -c 
lt;

它将找到所有 .cpp 文件并将它们编译为 .o 文件。 .o 文件将依赖于同名的 .cpp 文件和 .h 文件(以及 2dquicksort.h)。

First off, I am not an expert on Makefiles. I know the basics, but the Makefile in this answer will almost certainly have room for improvement. There are a lot of tricks and shortcuts that will allow you to handle dependencies and adding files better than hardcoding everything. However I think this example will be sufficient for your purposes and will possibly be more educational.

Second, I want to make sure you know the basic stages of building a project. You may already know this, but if you don't the following will be a bit confusing at first. There are essentially two steps: compiling and linking. Compiling converts your code to object code - it will convert a .cpp file to a .o file if successful. The next step is linking. This is where it sticks all the object code together to create an executable and links the function calls from one file to another (so if file1.cpp calls a function defined in file2.cpp, it's at this step that the file1.cpp figures out where the function actually is). There is more to it but that should be enough to make the following clear.

At this point you can just use g++ to compile and link your project (you can even do it in "one" step). This is quite cumbersome however, especially for any non-trivial project. It also makes it difficult to track files that have changed since you last compiled.

This is where Makefiles come in. A Makefile is a list of rules in the form:

target: dependencies
    command

(Make sure to use tabs not spaces, make probably won't work if you use spaces). If you run the command:

make some_target

Then make will look for the rule with some_target. If the target is a file, it will check the 'last modified' time stamp of the file, and it will check the time stamps of all the dependencies you have listed. If any of the dependencies have a later time stamp, it will run the command.

I'm going to have to make some assumptions about your project (namely, which files depend on which files) so you will probably have to modify the following, but here is a basic Makefile for your project (and remember, tabs not spaces. If you copy and paste this it won't work):

CC = g++
INCLUDE_DIRS = -I/path/to/boost

all: binary_file

clean:
    rm *.o
    rm binary_file

binary_file: simple_ls.o rawr.o converter.o
    $(CC) -o binary_file simple_ls.o rawr.o converter.o

rawr.o: rawr.h rawr.cpp 2dquicksort.h
    $(CC) -c rawr.cpp $(INCLUDE_DIRS)

simple_ls.o: simple_ls.h simple_ls.cpp 2dquicksort.h
    $(CC) -c simple_ls.cpp $(INC*emphasized text*LUDE_DIRS)

Running make or make all or make binary_file will cause all your files to be compiled if necessary and then linked to create an executable called binary_file. There are some improvements you can make, for example:

%.o: %.cpp %.h 2dquicksort.h
    $(CC) -c 
lt;

Which will find all the .cpp files and compile them in to .o files. The .o files will be dependent on a .cpp file and a .h file of the same name (and 2dquicksort.h).

终陌 2024-09-23 06:45:34

使用 @Job 的想法,我建议您将其留给某些 IDE 来完成。例如,在 Eclipse CDT 中构建一个项目并使用它自动生成的 make 文件。然后,您可以学习它,并及时更改它以完全满足您的需求。

Using @Job 's idea, I recommend you to leave it for some IDE to do. For example, Build a project in Eclipse CDT and use it's auto-generated make file. Then, you can kearn it and by the time change it to fit exactly your needs.

感性 2024-09-23 06:45:34

我更喜欢标准的项目描述,例如这个。换句话说,我认为对 makefile 的关注范围太窄了。

该项目描述的优点是简单。它可以使用 all 目标中的 make -C subdir -f Makefile all 来适应带有子目录的更复杂的项目。 subdir 当然是您的子目录,其中包含应构建的代码。

作者指出,创建和维护构建环境效率不高,因此您需要易于修改且易于理解的东西。我不一定想成为一名 makefile 专家。我认为这并不像许多人想象的那么有用。

我非常喜欢 hiltmon 的想法,所以我将它变成了 shell 脚本。我可能会用Python编写完成的项目,并询问作者是否可以为GitHub做出贡献。

I prefer a standard project description such as this one. In other words, I believe the focus on a makefile is too narrow.

The virtue of this project description is simplicity. It can be adapted to more complex projects with sub-directories using make -C subdir -f Makefile all in an all target. The subdir is of course your sub-directory with code that should be built.

The author points out that creating and maintaining build environments are not productive, so you want something that is easy to modify and that you understand. I would not necessarily set out to be a makefile expert. I don't think that's as useful as many think.

I like hiltmon's idea so much I'm turning it into a shell script. I may write the finished project in Python and ask the author if I can contribute to GitHub.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文