The Makefile needs only minor modifications; specifically, you need to change the values of the NAME
and BT_ADDR
variables (conveniently located at the top of the file) to match those of your project and EV3:
NAME=ProjectName # Replace with the name of your LeJOS Project BT_ADDR=XX:XX:XX:XX:XX:XX # Replace with bluetooth address of your EV3 which you found out in Chapter 5, Connecting with LeJOS PAN_IP_ADDR=10.0.1.2 SRC=$(wildcard src/*.java) $(wildcard src/*/*.java) JAR=build/libs/$(NAME).jar DEST=/home/lejos/programs .PHONY: default, build, run, connect, disconnect default: build build: $(JAR) $(JAR): $(SRC) build.gradle gradle build touch $(JAR) sync: $(JAR) scp $(JAR) ev3:$(DEST) touch sync run: sync ssh ev3 "cd $(DEST) && jrun -jar $(NAME).jar" connect: sudo pand --connect $(BT_ADDR) -n sudo ifconfig bnep0 $(PAN_IP_ADDR) disconnect: sudo pand -K
The Makefile, as it is currently written, makes a couple of assumptions about the project and the configuration of your system. I recommend that you adhere to these. If you choose not to, you will have to modify the Makefile accordingly.
The first assumption is that you have set up ssh config
as described in Chapter 5, Connecting with LeJOS, and named your connection ev3
such that running ssh ev3
connects you to the terminal inside EV3. This connection is used throughout the Makefile.
The second assumption is that all the Java code you have written has been placed inside the src
subfolder of the project's root folder. Since the same assumption is made in the standard build.gradle
file we use everywhere, this is not difficult to assure.
To use Make, simply place this Makefile inside the root folder of your project (on the same level as the build.gradle
file).
There are only two modifications required to make this sample Makefile work for your project, and both of them are placed right at the top of the file for ease of use. The first modification is to replace the value of the NAME
variable with the name of your project (which is also the name of the project's root folder as well as its main class and the generated executable file).
The second modification is needed only if you are using Bluetooth to connect your computer to EV3 (something that I will definitely recommend). In this case, replace the value of the BT_ADDR
variable with the Bluetooth address of EV3, as described in Chapter 5, Connecting with LeJOS.
Using the Make utility is extremely straightforward. Open a terminal and navigate to the project's root folder (which should now contain the Makefile). The command consists of the make
keyword followed by the name of the target you want achieved. The following table describes the targets defined by the Makefile and the actions they perform:
Targets |
Actions performed |
---|---|
|
Compiles the code and generates the executable |
|
Copies the |
|
Executes the |
|
Connects to EV3 using Bluetooth |
|
Disconnects from the Bluetooth network |
The sudo
prefix is required in the Debian family of Linux to execute the command using superuser privileges, which are required for interacting with the Bluetooth network.
A powerful feature of the Make utility is its ability to handle dependencies. For example, when you execute make run
, the first thing it does is check its dependencies. The run
target requires that the sync
target be achieved, which in turn has its own dependencies. If all of these dependencies have already been met, the make run
command simply uses SSH to execute the .jar
file on EV3.
If you modify any of your source code, Make detects this the next time it is run (by analyzing the timestamp on the file). The modification breaks a number of dependencies that must now be fulfilled. The Make utility does this automatically (the next time it is run) by compiling the code anew and copying the .jar
file to EV3 before it executes it. Thus, one can use only the make run
command all of the time, and it takes care of the entire compile-transfer-execute cycle automatically.
This ability highlights the power and utility of the Make tool. As a developer, one has to repeat the modify-compile-transfer-execute-test cycle constantly. Any tool that speeds up and simplifies this task is a fantastic aid.
This explanation is intended for users who are interested in understanding how the Makefile works. However, it is not a complete account since Make is a complicated utility, which is nonetheless worth learning.
When the Make utility is run, it looks for a file named Makefile in the current directory. The Makefile describes targets (basically, desired results) and the steps to achieve them. The targets can have other targets as dependencies. In this fashion, the Makefile can comprehensively and concisely describe the sequence of steps required to achieve an objective.
The dependencies of a target are described in the same line as the name of the target after the colon. If a target has no dependencies, the commands described under it (all of them preceded with a tab) are executed one by one as shell commands.
For example, the connect
target is defined as follows:
connect: sudo pand --connect $(BT_ADDR) -n sudo ifconfig bnep0 $(PAN_IP_ADDR)
When make connect
is executed, it looks up the target with the name connect
. It then searches for dependencies in the same line, which in this case, are none; so, it moves on to the commands defined below the target name. These are run one by one, first the pand
command and then the ifconfig
command, which create the Bluetooth network with EV3.
Compare this to the run
target:
run: sync ssh ev3 "cd $(DEST) && jrun -jar $(NAME).jar"
When make run
is executed, Make first encounters the sync
dependency. sync
is a special type of target, which is the name of an actual file. When a target (which is a file) is called as a dependency, its timestamp is compared with that of its own dependencies. If the target's timestamp is older than its dependencies, it means that the dependencies have changed recently; so, the target must be executed. In this fashion, the Make utility recursively analyzes timestamps and dependencies, executing only those targets that need to be and no more.
Note that run
depends on sync
, which in turn depends on the executable .jar
file. The .jar
file is also a target, and its dependencies are all of the Java source files and the build.gradle
file. If any of these are changed, the .jar
file will be recompiled and copied to EV3 before execution. Thus, Make is able to resolve all the dependencies and greatly simplify the compilation and deployment process.