Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

@heiner
Copy link
Contributor

@heiner heiner commented Jan 26, 2022

Hey!

I don't think you will want to immediately (or perhaps ever) merge this, I just thought it might be good to document somewhere how to build NetHack 3.7 via cmake out-of-source. I also have a cmake version for NetHack 3.6 (harder, as it requires dealing with dgn_comp, lvl_comp etc).

This doesn't yet include building the Guildebook or flags like WANT_LIBNH but they would be easy to add if there is interest.

To build:

mkdir build && cd build 
cmake .. -GNinja && ninja && cmake --install .
./nethack

@dextercd
Copy link
Contributor

For me CMake is much better than the Makefiles approach so I'm happy to see this PR. I ran into some minor issues.

I get the following error when using the CMake build:

ninja: error: 'lua/src/fetch-lua/src/liblua.a', needed by 'nethack', missing and no known rule to make it

Applying the following patch seems to help:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c2678eb7..de2a4819f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,6 +54,7 @@ ExternalProject_Add(
   BUILD_IN_SOURCE TRUE
   CONFIGURE_COMMAND ""
   BUILD_COMMAND make
+  BUILD_BYPRODUCTS <BINARY_DIR>/src/liblua.a
   INSTALL_COMMAND ""
   STEP_TARGETS build)

After that I get this error:

$ cmake --build . -v
[1/136] : && /usr/bin/cc   util/CMakeFiles/makedefs.dir/makedefs.c.o util/CMakeFiles/makedefs.dir/__/src/monst.c.o util/CMakeFiles/makedefs.dir/__/src/objects.c.o util/CMakeFiles/makedefs.dir/__/src/alloc.c.o util/CMakeFiles/makedefs.dir/__/src/date.c.o -o util/makedefs   && :
FAILED: util/makedefs 
: && /usr/bin/cc   util/CMakeFiles/makedefs.dir/makedefs.c.o util/CMakeFiles/makedefs.dir/__/src/monst.c.o util/CMakeFiles/makedefs.dir/__/src/objects.c.o util/CMakeFiles/makedefs.dir/__/src/alloc.c.o util/CMakeFiles/makedefs.dir/__/src/date.c.o -o util/makedefs   && :
/usr/bin/ld: util/CMakeFiles/makedefs.dir/__/src/alloc.c.o: in function `alloc':
alloc.c:(.text+0x34): undefined reference to `panic'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

Applying the following patch seems to help:

diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt
index c7ede9b38..70f1174de 100644
--- a/util/CMakeLists.txt
+++ b/util/CMakeLists.txt
@@ -1,5 +1,5 @@
 set(MAKEDEFS_SRC makedefs.c ${NH_SRC}/monst.c ${NH_SRC}/objects.c
-                 ${NH_SRC}/alloc.c ${NH_SRC}/date.c)
+                 ${NH_SRC}/alloc.c ${NH_SRC}/date.c panic.c)
 
 # TODO: Re-add onames.h once "prob error for class 4 (28%)" error is fixed.
 set(MAKEDEFS_HEADERS ${NH_INC_GEN}/date.h # ${NH_INC_GEN}/onames.h

After this the nethack target gets a bunch of linker errors because of liblua.a uses math functions but is not linking to libm.a. liblua.a and loadlib.c also require it to link to libdl.a for dlopen, dlclose etc.

Applying the following patch fixes the issue.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index de2a4819f..c26c3ce53 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,7 +93,7 @@ file(
 
 # nethack executable.
 add_executable(nethack ${NETHACK_SRC})
-target_link_libraries(nethack ncurses ${TOPLUALIB})
+target_link_libraries(nethack ncurses ${TOPLUALIB} ${CMAKE_DL_LIBS} m)
 
 # TODO: Add check-dlb, Guidebook
 add_dependencies(nethack util dat lua_support)

After this nethack compiled cleanly 😄 I pushed these changes here as well: https://github.com/dextercd/NetHack/tree/NetHack-3.7-cmake

CMakeLists.txt Outdated Show resolved Hide resolved
Comment on lines +92 to +95
add_custom_command(
DEPENDS $<TARGET_FILE:makedefs> bogusmon.txt engrave.txt epitaph.txt
OUTPUT bogusmon epitaph engrave
COMMAND $<TARGET_FILE:makedefs> ARGS -s)
Copy link
Contributor

@dextercd dextercd Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the target name directly in the COMMAND argument which will also automatically register it as a dependency (it seems that that's not actually the case). That's a bit tidier IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify this comment? Are you suggesting a change like this?

-   COMMAND $<TARGET_FILE:makedefs> ARGS -s)
+   COMMAND makedefs ARGS -s)

I wasn't sure that this would include the full path. But perhaps I am misunderstanding your suggestion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what I meant. This is a documented feature:

If COMMAND specifies an executable target name (created by the add_executable() command), it will automatically be replaced by the location of the executable created at build time if .. [cross compile details] ..

This is how I use add_custom_command most of the time. Alternatively I put a variable that contains the path to a program that was found via find_program.

The target name syntax could be confused with referring to a program that is on the $PATH. But that's not a common use case in my experience.

I should clarify that this is just a minor nitpick. I've never used TARGET_FILE for this and don't remember seeing it anywhere else either, but it's readable and I'm sure it does the job. 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! But the cmake documentation continues like this:

Arguments to COMMAND may use generator expressions. Use the TARGET_FILE generator expression to refer to the location of a target later in the command line (i.e. as a command argument rather than as the command to execute).

(OK, so in our case it is the command itself, so I guess we shouldn't use TARGET_FILE?)

Whenever one of the following target based generator expressions are used as a command to execute or is mentioned in a command argument, a target-level dependency will be added automatically so that the mentioned target will be built before any target using this custom command (see policy CMP0112).

TARGET_FILE
TARGET_LINKER_FILE
TARGET_SONAME_FILE
TARGET_PDB_FILE

So this style introduces a dependency (which we want in this case).

Overall, cmake is such a highly non-uniform language, it's kind of sad it became standard (over, say, something closer to bazel).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I hadn't seen that but some testing reveals that it doesn't quite work how I'd expect.

I think I get it now.. For the COMMAND argument, using either the target name or $<TARGET_FILE:target_name> creates a target-level dependency but neither introduce a file-level dependency.

This target-level dependency does NOT add a file-level dependency that would cause the custom command to re-run whenever the executable is recompiled. List target names with the DEPENDS option to add such file-level dependencies.

File-level dependence is what I had in mind in my previous comments. TBH I didn't know CMake had different kinds of dependencies.

I like CMake but it definitely has its sharp edges (and mushy ones.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand the difference between target-level dependencies and file-level dependencies, but I gather the latter means: If a target has a file-level dependency on a binary (file), it will cause that binary file to be build, but if it's already present it is not rebuild?

By the way if memory serves some of the $<TARGET_FILE:target_name> syntax I introduced after I noticed my cmake setup breaks when applied to a NetHack which also has build artefacts in-source (e.g., run make, then run cmake). CMake chose the wrong files to depend on in some cases, this commit tried to work around that, but might have overdone it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes from what I can tell that is the difference between target and file-level dependencies. Rebuilding the data files when the binary has change makes most sense to me.

Hm, that's odd. I may play around with the scenario you described. Was the CMake build an in-source or out-of-source build? Anyhow, keeping it as TARGET_FILE is good. Please consider this conversation resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I'm sorry, I wasn't quite clear.

Issues can occur when calling cmake after using NetHacks current/standard Makefile setup, e.g., on Linux:

cd sys/unix
sh setup.sh hints/linux
cd ../..
make
mkdir build && cd build
cmake .. -GNinja
ninja

The issue is that this causes in-source build artefacts to be picked up by cmake, as opposed to their out-of-source targets. The commit I linked above is trying to work around that; I don't remember if using $<TARGET_FILE:target_name> truly helped with this; what definitely helped was using absolute paths everywhere.

Updates to NetHack 3.7 CMakeLists.txt
@heiner
Copy link
Contributor Author

heiner commented Jan 27, 2022

Thanks @dextercd for your fixes! I'm not sure how this could work for me without this. I've merged your commits into my branch.

@nhcopier nhcopier deleted the branch NetHack:NetHack-3.7 January 27, 2022 16:20
@nhcopier nhcopier closed this Jan 27, 2022
@dextercd
Copy link
Contributor

Looks like the NetHack-3.7 branch was deleted and recreated, which closes all pull requests targeting this branch.. That was probably not intentional 😕

@nhcopier
Copy link
Contributor

nhcopier commented Jan 27, 2022 via email

@nhmall nhmall reopened this Jan 27, 2022
heiner pushed a commit to facebookresearch/nle that referenced this pull request Jan 31, 2022
This was disliked by a reviewer in NetHack/NetHack#662
but corresponds to what NetHack's Makefiles do.
CMakeLists.txt Outdated Show resolved Hide resolved
Comment on lines +92 to +95
add_custom_command(
DEPENDS $<TARGET_FILE:makedefs> bogusmon.txt engrave.txt epitaph.txt
OUTPUT bogusmon epitaph engrave
COMMAND $<TARGET_FILE:makedefs> ARGS -s)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes from what I can tell that is the difference between target and file-level dependencies. Rebuilding the data files when the binary has change makes most sense to me.

Hm, that's odd. I may play around with the scenario you described. Was the CMake build an in-source or out-of-source build? Anyhow, keeping it as TARGET_FILE is good. Please consider this conversation resolved

Flone-dnb added a commit to Flone-dnb/NetHack that referenced this pull request Jan 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.