Why is no one using make for Java?

前端 未结 17 1440
生来不讨喜
生来不讨喜 2020-12-12 09:09

Just about every Java project that I\'ve seen either uses Maven or Ant. They are fine tools and I think just about any project can use them. But what ever happened to make

相关标签:
17条回答
  • 2020-12-12 09:50

    Short answer: Because make isn't good. Even on the C front you see many alternatives popping up.

    Long answer: make has several flaws that make it barely suitable for compiling C, and unsuitable at all for compiling Java. You can force it to compile Java, if you want, but expect running into issues, some of which do not have a suitable solution or workaround. Here are a few:

    Dependency resolution

    make inherently expects files to have a tree-like dependency on each other, in which one file is the output of building several others. This already backfires in C when dealing with header files. make requires a make-specific include file to be generated to represent the dependency of a C file on its header files, so a change to the latter would cause the prior to be rebuilt. However, since the C file itself isn't recreated (merely rebuilt), make often requires specifying the target as .PHONY. Fortunately, GCC supports generating those files automatically.

    In Java, dependency can be circular, and there's no tool for auto-generating class dependencies in make format. ant's Depend task can, instead, read the class file directly, determine which classes it imports, and delete the class file if any of them are out of date. Without this, any non-trivial dependency may result in you being forced to use repeated clean builds, removing any advantage of using a build tool.

    Spaces in filenames

    While neither Java nor C encourage using spaces in your source code filenames, in make this can be problem even if the spaces are in the file path. Consider, for example, if your source code exists in C:\My Documents\My Code\program\src. This would be enough to break make. This is because make treats filenames as strings. ant treats paths as special objects.

    Scanning files for build

    make requires explicitly setting which files are to be built for each target. ant allows specifying a folder which is to be auto-scanned for source files. It may seem like a minor convenience, but consider that in Java each new class requires a new file. Adding files to the project can become a big hassle fast.

    And the biggest problem with make:

    make is POSIX-dependent

    Java's motto is "compile once run everywhere". But restricting that compilation to POSIX-based systems, in which Java support is actually the worst, is not the intention.

    Build rules in make are essentially small bash scripts. Even though there is a port of make to Windows, for it to work properly, it has to be bundled with a port of bash, which includes a POSIX emulation layer for the file system.

    This comes in two varieties:

    1. MSYS which tries to limit the POSIX translation to file paths, and can therefore have unpleasant gotchas when running external tools not made especially for it.

    2. cygwin which provides a complete POSIX emulation. The resulting programs, however, tend to still rely on that emulation layer.

    For that reason, on Windows, the standard build tool isn't even make at all, but rather MSBuild, which is also an XML-based tool, closer in principle to ant.

    By contrast, ant is built in Java, can run everywhere, and contains internal tools, called "tasks", for manipulating files and executing commands in a platform-independent way. It's sufficiently versatile that you can actually have an easier time building a C program in Windows using ant than using make.

    And one last minor one:

    Even C programs don't use make natively

    You may not initially notice this, but C programs generally aren't shipped with a Makefile. They are shipped with a CMakeLists.txt, or a bash configuration script, which generates the actual Makefile. By contrast, the source of a Java program built using ant is shipped with an ant script pre-built. A Makefile is a product of other tools - That's how much make is unsuitable to be a build tool on its own. ant is standalone, and deals with everything you need for your Java build process, without any additional requirements or dependencies.

    When you run ant on any platform, it Just Works(tm). You can't get that with make. It's incredibly platform and configuration dependent.

    0 讨论(0)
  • 2020-12-12 09:51

    Ant and later Maven were designed to solve some headaches caused by Make ( while creating new ones in the process ) It is just evolution.

    ...Soon thereafter, several open source Java projects realized that Ant could solve the problems they had with Makefiles....

    From http://ant.apache.org/faq.html#history

    Whether they solve anything or just create an extra format to learn is a subjective topic. The truth is that's pretty much the history of every new invention: The creator says it solves a lot of problems and the original users say those are virtues.

    The main advantage it has, is the possibility to integrate with java.

    I guess a similar history would be with rake for instance.

    0 讨论(0)
  • 2020-12-12 09:52

    Once upon a time I worked on a Java project that used gmake. My recollection is hazy but IIRC we had a hard time dealing with the package directory structure that javac expects. I also remember that building JAR files was a hassle unless you had something trivial.

    0 讨论(0)
  • 2020-12-12 09:52

    Ant and Maven approach the build dependency graph and the management of it from a more 'modern' view... But as Oscar says, they created their own problems while attempting to address the old problems with make.

    0 讨论(0)
  • 2020-12-12 09:54

    Actually, make can handle the recompilation in one command of all outdated java files. Change the first line if you don't want to compile all files in the directory or want a specific order...

    JAVA_FILES:=$(wildcard *.java)
    #
    # the rest is independent of the directory
    #
    JAVA_CLASSES:=$(patsubst %.java,%.class,$(JAVA_FILES))
    
    .PHONY: classes
    LIST:=
    
    classes: $(JAVA_CLASSES)
            if [ ! -z "$(LIST)" ] ; then \
                    javac $(LIST) ; \
            fi
    
    $(JAVA_CLASSES) : %.class : %.java
            $(eval LIST+=$$<)
    
    0 讨论(0)
  • 2020-12-12 09:56

    The fundamental issue with Make and Java is that Make works on the premise that you have specify a dependency, and then a rule to resolve that dependency.

    With basic C, that typically "to convert a main.c file to a main.o file, run "cc main.c".

    You can do that in java, but you quickly learn something.

    Mostly that the javac compiler is slow to start up.

    The difference between:

    javac Main.java
    javac This.java
    javac That.java
    javac Other.java
    

    and

    javac Main.java This.java That.java Other.java
    

    is night and day.

    Exacerbate that with hundreds of classes, and it just becomes untenable.

    Then you combine that with the fact that java tends to be organized as groups of files in directories, vs C and others which tend towards a flatter structure. Make doesn't have much direct support to working with hierarchies of files.

    Make also isn't very good at determining what files are out of date, at a collection level.

    With Ant, it will go through and sum up all of the files that are out of date, and then compile them in one go. Make will simply call the java compiler on each individual file. Having make NOT do this requires enough external tooling to really show that Make is not quite up to the task.

    That's why alternatives like Ant and Maven rose up.

    0 讨论(0)
提交回复
热议问题