diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | .gitlab-ci.yml | 74 | ||||
-rw-r--r-- | .gitmodules | 2 | ||||
-rw-r--r-- | CMakeLists.txt | 188 | ||||
-rw-r--r-- | COPYING | 2 | ||||
-rw-r--r-- | Makefile.in | 88 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rwxr-xr-x | configure | 10 | ||||
m--------- | deps/attoconf | 0 | ||||
-rw-r--r-- | generate.mk (renamed from generate.make) | 0 | ||||
-rw-r--r-- | src/conf/install.hpp.in (renamed from src/conf/install.hpp) | 7 | ||||
-rw-r--r-- | src/conf/version.hpp.in (renamed from src/conf/version.hpp) | 21 | ||||
-rw-r--r-- | src/main-gdb-head.py | 2 | ||||
-rw-r--r-- | src/map/script-parse.py | 2 | ||||
-rw-r--r-- | src/mmo/version.cpp | 2 | ||||
-rw-r--r-- | src/shared/lib.cpp | 2 | ||||
-rwxr-xr-x | tools/bs-align | 2 | ||||
-rwxr-xr-x | tools/colorize | 4 | ||||
-rwxr-xr-x | tools/config.py | 10 | ||||
-rwxr-xr-x | tools/debug-debug-scripts | 9 | ||||
-rw-r--r-- | tools/debug-debug.gdb | 6 | ||||
-rwxr-xr-x | tools/indenter | 7 | ||||
-rwxr-xr-x | tools/pp-indent | 2 | ||||
-rwxr-xr-x | tools/protocol.py | 125 | ||||
-rw-r--r-- | version.mk (renamed from version.make) | 31 |
25 files changed, 456 insertions, 148 deletions
@@ -9,10 +9,12 @@ /src/proto2/ /src/debug-debug/ /src/*/*_conf.[ch]pp +/src/conf/version.hpp # tags file /tags # generated by configure /Makefile +/src/conf/install.hpp /config.status /lib # generated by python @@ -32,3 +34,7 @@ # generic build /build/ + +# CI build +/build-atto/ +/build-cmake/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f7c750a..0368723 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,6 +8,7 @@ variables: &base_vars # Depth of clone. If no tag is made after this many commits, then # the git describe call and version header generation will fail. GIT_DEPTH: 100 # Will break again eventually. + GIT_SUBMODULE_STRATEGY: normal .prerequisites: &prerequisites before_script: @@ -15,21 +16,21 @@ variables: &base_vars - apt-get update - apt-get install -y -qq $INSTALL_PACKAGES $DEBIAN_COMMON_PACKAGES - # Active server OS? -re:ubuntu1804:build: +re:ubuntu1804-attoconf:build: <<: *prerequisites stage: build image: ubuntu:18.04 variables: <<: *base_vars - INSTALL_PACKAGES: python + INSTALL_PACKAGES: python3 script: - echo "Building TMW Athena $CI_BUILD_NAME" - - git submodule update --init - git fetch -t - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" - - ./configure --user + - mkdir build-atto + - cd build-atto + - ../configure --user - make - whoami - make install @@ -37,23 +38,20 @@ re:ubuntu1804:build: untracked: true expire_in: 30 mins - - - # Next server OS? -re:ubuntu2204:build: +re:ubuntu2204-attoconf:build: <<: *prerequisites stage: build image: ubuntu:22.04 variables: <<: *base_vars - INSTALL_PACKAGES: python2 + INSTALL_PACKAGES: python3 script: - - ln -s /usr/bin/python2 /usr/bin/python - - git submodule update --init - git fetch -t - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" - - ./configure --user + - mkdir build-atto + - cd build-atto + - ../configure --user - make - whoami - make install @@ -61,31 +59,69 @@ re:ubuntu2204:build: untracked: true expire_in: 30 mins - +# Next server OS, with cmake +re:ubuntu2204:build: + <<: *prerequisites + stage: build + image: ubuntu:22.04 + variables: + <<: *base_vars + INSTALL_PACKAGES: python3 cmake + script: + - git fetch -t + - printf "Building TMW Athena version %s\n" "$(git describe --tags HEAD)" + - mkdir build-cmake + - cd build-cmake + - cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. + - make + - whoami + - make install + artifacts: # required for test stage + untracked: true + expire_in: 30 mins # Disabled. fails with: # (1) GDB failing to resolve a type # (2) /usr/bin/ld: Dwarf Error: Can't find .debug_ranges section. -.re:ubuntu1804:test: +.re:ubuntu1804-attoconf:test: <<: *prerequisites stage: test image: ubuntu:18.04 + needs: ["ubuntu1804-attoconf:build"] + variables: + <<: *base_vars + INSTALL_PACKAGES: python3 gdb + script: + - printf "Testing TMW Athena version %s\n" "$(git describe --tags HEAD)" + - cd build-atto + - make test + + +# Enabled tests +re:ubuntu2204-attoconf:test: + <<: *prerequisites + stage: test + image: ubuntu:22.04 + needs: ["re:ubuntu2204-attoconf:build"] variables: <<: *base_vars - INSTALL_PACKAGES: python gdb + INSTALL_PACKAGES: python3 gdb script: - printf "Testing TMW Athena version %s\n" "$(git describe --tags HEAD)" + - cd build-atto - make test -re:ubuntu2204:test: +# Disabled. Tests are not supported yet by the CMake project. +.re:ubuntu2204:test: <<: *prerequisites stage: test image: ubuntu:22.04 + needs: ["re:ubuntu2204:build"] variables: <<: *base_vars - INSTALL_PACKAGES: python2 gdb + INSTALL_PACKAGES: python3 gdb script: - - ln -s /usr/bin/python2 /usr/bin/python - printf "Testing TMW Athena version %s\n" "$(git describe --tags HEAD)" + - cd build-cmake - make test diff --git a/.gitmodules b/.gitmodules index 8197e60..48c5d1f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "deps/attoconf"] path = deps/attoconf - url = https://github.com/o11c/attoconf.git + url = https://github.com/Freeyorp/attoconf [submodule "deps/googletest"] path = deps/googletest url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..16e251c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,188 @@ +cmake_minimum_required(VERSION 3.10) + +# Function for conveniently capturing git output, used to set version related variables +find_package(Git REQUIRED) +function(git_capture_output var) + execute_process(COMMAND ${GIT_EXECUTABLE} ${ARGN} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${var} + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + message(STATUS "${var} = ${${var}}") + set(${var} ${${var}} PARENT_SCOPE) +endfunction() + +git_capture_output(VERSION_FULL describe --tags) +git_capture_output(VERSION_HASH rev-parse HEAD) + +# Capture the major.minor.patch part of the version based on the last tag +string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" VERSION ${VERSION_FULL}) + +# Capture the tweak part of the version +if(${VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-([0-9]+)-g[0-9a-f]+$") + set(VERSION "${VERSION}.${CMAKE_MATCH_1}") +else() + set(VERSION "${VERSION}.0") +endif() + +project(tmwAthena VERSION ${VERSION} LANGUAGES CXX) + +# Prefer to use G++ as the compiler +set(CMAKE_CXX_COMPILER g++) +# Set C++ standard to C++11 +# Note we want -std=c++11, not -std=gnu++11, as we want to avoid GNU extensions +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Some sources and includes are generated, such as the protocol headers. +# We defer to generate.make for these rules. +# Note that these are raw Makefile rules, not CMake rules, so a simple +# add_custom_command() won't work. +execute_process(COMMAND make -f ${CMAKE_SOURCE_DIR}/generate.mk + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + +# The generate target must be re-run when the scripts change +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + "${PROJECT_SOURCE_DIR}/generate.mk" + "${PROJECT_SOURCE_DIR}/tools/config.py" + "${PROJECT_SOURCE_DIR}/tools/protocol.py" +) + +# Search through the tree for sources +# For each subfolder in src, add all .cpp, .hpp and .tcc files to a subfolder's SOURCES +# variable. +set(ALL_SOURCES "") +foreach(dir admin ast char compat conf generic high ints io login map mmo net proto-base range sexpr shared strings tests wire) + file(GLOB_RECURSE ${dir}_SOURCES CONFIGURE_DEPENDS + src/${dir}/*.cpp + src/${dir}/*.hpp + src/${dir}/*.tcc) + # Exclude any _test.cpp files from the build + set(ALL_SOURCES ${ALL_SOURCES} ${${dir}_SOURCES}) + list(FILTER ${dir}_SOURCES EXCLUDE REGEX ".*_test.cpp") + message("Adding sources in ${dir}: ${${dir}_SOURCES}") +endforeach() + +# All targets include the include/ directory +include_directories(include) + +# We want -fvisibility=hidden for regular objects, but not shared libraries. +# CMake provides a helpful preset for this. +# FIXME this is currently broken +#set(CMAKE_CXX_VISIBILITY_PRESET hidden) +# General purpose build flags. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fstack-protector -fno-strict-aliasing -flto") +# Enable link time optimization, and track function and data sections. We let +# the linker remove unused code. +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -ffunction-sections -fdata-sections -Wl,--gc-sections") +# Next, add warnings +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +# Add debug information +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + +# Vendor Name: String (no newlines, no parentheses) +# This is usually one word, and does not (usually) change over time. +# (Examples: Gentoo, Debian, Fedora, Ubuntu) +set(VENDOR_NAME Vanilla) +# Vendor Point: Integer (max value 65535) +# This is intended to be the "packaging revision number", assuming that's +# an integer. At a minimum, please try to make it nonzero if you have +# any non-upstream patches (unconditionally nonzero is also okay). +# (If your revision 0 package has patches ... please be nicer to upstream) +set(VENDOR_POINT 0) +# URL where the source may be found (after searching for version number). +# See AGPLv3 section 13 +set(VENDOR_SOURCE https://git.themanaworld.org/legacy/tmwa) + +# Convenience +set(VERSION_STRING "TMWA ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} dev${PROJECT_VERSION_TWEAK} +${VENDOR_POINT} (${VENDOR_NAME})") +set(VERSION_DOTS "${PROJECT_VERSION}.${VENDOR_POINT}") + +include(GNUInstallDirs) +set(PACKAGEDATADIR "${CMAKE_INSTALL_FULL_DATAROOTDIR}/tmwa") +set(LOCALSTATEDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}") +set(SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}") + +# Generate the install.hpp and version.hpp files. +configure_file(src/conf/install.hpp.in src/conf/install.hpp @ONLY) +configure_file(src/conf/version.hpp.in src/conf/version.hpp @ONLY) +set(conf_SOURCES ${conf_SOURCES} src/conf/install.hpp src/conf/version.hpp) +# And have the build search for files in the build directory. +# Note that #includes with generated files should use a path relative to the +# top level source or build directory. +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# Add a shared library: libtmwa-shared.so.0 +# When we add_executable later, we need to link against this library. +add_library(tmwa-shared SHARED ${shared_SOURCES} + src/io/dir.cpp + src/io/fd.cpp + src/io/read.cpp + src/io/write.cpp + ${strings_SOURCES} +) +# SO versioning +set(ABI_VERSION 0) +set_target_properties(tmwa-shared PROPERTIES + VERSION ${ABI_VERSION}.${VERSION_DOTS} + SOVERSION ${ABI_VERSION}) + +# We have four binaries we want to build: tmwa-{login,char,map,admin} +add_executable(tmwa-login ${login_SOURCES} + ${generic_SOURCES} + ${high_SOURCES} + ${io_SOURCES} + ${mmo_SOURCES} + ${net_SOURCES} + ${wire_SOURCES} +) +target_link_libraries(tmwa-login tmwa-shared) + +add_executable(tmwa-char ${char_SOURCES} + ${generic_SOURCES} + ${high_SOURCES} + ${io_SOURCES} + ${mmo_SOURCES} + ${net_SOURCES} + ${wire_SOURCES} +) +target_link_libraries(tmwa-char tmwa-shared) + +add_executable(tmwa-map ${map_SOURCES} + ${ast_SOURCES} + ${compat_SOURCES} + ${generic_SOURCES} + ${high_SOURCES} + ${io_SOURCES} + ${mmo_SOURCES} + ${net_SOURCES} + ${wire_SOURCES} + ) +target_link_libraries(tmwa-map tmwa-shared) + +add_executable(tmwa-admin ${admin_SOURCES} + ${generic_SOURCES} + ${high_SOURCES} + ${io_SOURCES} + ${mmo_SOURCES} + ${net_SOURCES} + ${wire_SOURCES} +) +target_link_libraries(tmwa-admin tmwa-shared) + +# TODO: Call make -f ${CMAKE_SOURCE_DIR}/generate.mk clean to clean up the +# generated files. We want this to be run every time we call make clean. + +# Install targets +install(TARGETS tmwa-login tmwa-char tmwa-map tmwa-admin tmwa-shared + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +# Install shared configuration and data +install(FILES etc/tmwa/shared.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/tmwa) +install(FILES share/tmwa/shared.data DESTINATION ${CMAKE_INSTALL_DATADIR}/tmwa) + +# Make sure there is a var directory +install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LOCALSTATEDIR}/tmwa) @@ -5,7 +5,7 @@ This combination is explicitly allowed by section 13 of the licenses. See gpl-3.0.txt or agpl-3.0.txt for specific terms. In order to make life easy for users who run this software publicly, -please set VENDOR_SOURCE in version.make if you make any modifications. +please set VENDOR_SOURCE in version.mk if you make any modifications. History: diff --git a/Makefile.in b/Makefile.in index 10f909c..075c107 100644 --- a/Makefile.in +++ b/Makefile.in @@ -152,7 +152,7 @@ $(info The Road goes ever on and on ...) endif endif -include ${SRC_DIR}/version.make +include ${SRC_DIR}/version.mk ifeq (${ENABLE_SHARED},yes) LIB_SUFFIX_FAKE := so @@ -184,12 +184,13 @@ export PATH:=$(realpath ${SRC_DIR}/tools):${PATH} SHELL=bash # need to generate source files before path lists -$(shell make -f ${SRC_DIR}/generate.make >&2) +$(shell make -f ${SRC_DIR}/generate.mk >&2) stamp/generated.stamp: # if you get here, the shell above failed false # path lists +GENERATED_FILES := src/conf/version.hpp REAL_SOURCES := $(shell cd ${SRC_DIR}; find src/ -name '*.cpp') REAL_HEADERS := $(shell cd ${SRC_DIR}; find include/ src/ -name '*.hpp' -o -name '*.tcc') PIES := $(shell cd ${SRC_DIR}; find src/ -name '*.py') @@ -283,9 +284,9 @@ endif # This needs to edit CXX instead of CXXFLAGS in order to make # the %.ii rule work. ifeq (${ENABLE_CYGWIN_HACKS},yes) -override CXX += -std=gnu++0x +override CXX += -std=gnu++11 else -override CXX += -std=c++0x +override CXX += -std=c++11 endif CXXFLAGS += -fstack-protector @@ -333,9 +334,60 @@ include ${DEPENDS} endif thisdir := $(abspath .) + #$(foreach root,${PATTERN_ROOTS},$(info pre-root: ${root} := $(value ${root}))$(info )) # can't do $(filter %.hpp yet) -$(foreach root,${PATTERN_ROOTS},$(eval ${root} := $(sort $(patsubst ${thisdir}/%,%,$(abspath $(patsubst ${SRC_DIR}/%,%,$(wildcard $(value ${root})) $(filter conf-raw/%.h,$(value ${root})))))))) + +# Sanitize the dependencies. +# +# ${root} has a value like "mmo/version", and ${mmo/version} in turn has the +# value of all of its dependencies (from the %.d files). +# +# This reassigns the *value of the value* of ${root} to be: +# - sorted +# - relative and simplified: it's stripped of any absolute path relative to +# the current directory after being converted to an absolute path. +# This also converts paths from being relative to the build directory to +# being relative to the source directory, if they differ. +# This simplifies any construct such as: +# ../src/mmo/../strings/zstring.tcc +# to: +# src/strings/zstring.tcc +# - only files which either exist (the purpose of the wildcard function), +# are in the conf-raw directory (the first filter function), or +# are listed in the GENERATED_FILES variable (the second filter function). +# This means that if there are any build-time generated files added, this +# needs to be modified to not filter them out. +# +# The end result for each root will look something like: +# mmo/version := conf-raw/int-VENDOR_POINT.h conf-raw/int-VERSION_DEVEL.h [...] +# src/strings/zstring.tcc src/wire/fwd.hpp + +# Firstly, make the paths relative and simplified. +$(foreach root,${PATTERN_ROOTS},$(eval \ + ${root} := $(sort $(patsubst ${thisdir}/%,%, \ + $(abspath $(patsubst ${SRC_DIR}/%,%, $(value ${root}))) \ + )) \ +)) + +# Secondly, make sure that the files actually exist, or are files we expect to +# generate ourselves. Sort the result for readability. +# Note that we re-add and remove the ${SRC_DIR} prefix when first testing for +# existence, as we need to test for existence relative to our build directory. +# The second wildcard test doesn't add a ${SRC_DIR} prefix, but does strip it, +# handling the case where the file is specified relative to the source +# directory (mostly the case in test sources). +$(foreach root,${PATTERN_ROOTS},$(eval \ + ${root} := $(sort \ + $(patsubst ${SRC_DIR}/%,%,$(wildcard $(addprefix ${SRC_DIR}/, \ + $(value ${root}) \ + ))) \ + $(patsubst ${SRC_DIR}/%,%,$(wildcard ${SRC_DIR})) \ + $(filter conf-raw/%.h,$(value ${root})) \ + $(filter ${GENERATED_FILES},$(value ${root})) \ + ) \ +)) + # have to redo what we undid to get it as a variable $(foreach root,${PATTERN_ROOTS},$(eval obj/${root}.ii obj/${root}.ll obj/${root}.bc obj/${root}.s obj/${root}.pdc.o obj/${root}.pic.o obj/${root}.d : $(value ${root})) ) #$(foreach root,${PATTERN_ROOTS},$(info post-root: ${root} := $(value ${root}))$(info )) @@ -386,6 +438,7 @@ vpath include/%.hpp ${SRC_DIR} vpath src/%.tcc ${SRC_DIR} vpath tools/% ${SRC_DIR} vpath src/%.py ${SRC_DIR} +vpath src/%.in ${SRC_DIR} .DELETE_ON_ERROR: .DEFAULT_GOAL := all @@ -437,6 +490,10 @@ obj/%.d: src/%.cpp | stamp/generated.stamp ${CXX} ${CPPFLAGS} -DGENERATING_DEPENDENCIES ${CXXFLAGS} -MG -MM \ -MT '$(patsubst obj/%.d,%,$@) := ' \ -MF $@ $< +# -MG takes the include parameter as-is without prepending the path whenever +# it's not found, and presumed to be a not-yet generated file. +# #include statements for generated files should always be relative to the +# source (or build) directory. endif # the above SRC_DIR replacement is not really safe, but it works okayish. obj/%.ii: src/%.cpp @@ -508,8 +565,8 @@ obj/gtest%.pdc.o: ${GTEST_DIR}/src/gtest%.cc DTEST_OBJS := $(filter obj/debug-debug/%.pdc.o,${PDC_OBJECTS}) DTEST_STAMPS := $(patsubst bin/tests/%.elf,stamp/run-%.stamp,${DTEST_BINARIES}) -${DTEST_OBJS}: override CXXFLAGS += -g -O0 -gdwarf-3 -${DTEST_STAMPS}: override TESTER=${GDB} -return-child-result -nx -batch -ex 'python file_to_load = "$<"' -x ${SRC_DIR}/tools/debug-debug.gdb --args false +${DTEST_OBJS}: override CXXFLAGS += -ggdb -O0 +${DTEST_STAMPS}: override TESTER=LD_LIBRARY_PATH="./lib" ${GDB} -return-child-result -nx -batch -ex 'python file_to_load = "$<"' -x ${SRC_DIR}/tools/debug-debug.gdb --args false ${DTEST_STAMPS}: tools/debug-debug.gdb test: test-direct @@ -539,7 +596,7 @@ test: test-rank-fwd test-rank-fwd: ${CHECK_RANK_FWDS} stamp/%.rank: src/% $(MKDIR_FIRST) - includes=$$(grep '#include.*".*/.*"' $< | sed 's/^[^"]*"//;s/"[^"]*$$//;s:/[^/]*$$::' | sort -u | fgrep -vx -e '..' -e 'conf-raw' -e '../conf'); \ + includes=$$(grep '#include.*".*/.*"' $< | sed 's/^[^"]*"//;s/"[^"]*$$//;s:/[^/]*$$::' | sort -u | fgrep -vx -e '..' -e 'conf-raw' -e '../conf' -e 'src/conf'); \ for inc in $$includes; do if ! test -f ${<D}/fwd.hpp; then continue; fi; echo fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp; fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp || { echo ${<D}/fwd.hpp:''23: error: No $${inc}/fwd.hpp; exit 1; }; done touch $@ @@ -682,21 +739,22 @@ conf-raw/bool-%.h: FORCE conf-raw/str-%.h: FORCE $(MKDIR_FIRST) @echo '#define $* "$(value $*)"_s' | maybe-replace $@ -FORCE: ; + +FORCE:: ; .PHONY: FORCE -override CPPFLAGS += -I . -I ${SRC_DIR}/include +override CPPFLAGS += -I. -I${SRC_DIR} -I${SRC_DIR}/include # distribution tarballs # this only works from within a git checkout -dist/%/version.make: +dist/%/version.mk: $(MKDIR_FIRST) - git --git-dir=${SRC_DIR}/.git show HEAD:version.make > $@ + git --git-dir=${SRC_DIR}/.git show HEAD:version.mk > $@ sed 's/^VERSION_FULL := .*/#&\nVERSION_FULL := ${VERSION_FULL}/' -i $@ sed 's/^VERSION_HASH := .*/#&\nVERSION_HASH := ${VERSION_HASH}/' -i $@ -dist/%-src.tar: dist/%/version.make +dist/%-src.tar: dist/%/version.mk git --git-dir=${SRC_DIR}/.git archive --prefix=$*/ -o $@ HEAD - ( mtime="$$(git --git-dir=${SRC_DIR}/.git log -n1 --pretty=%ci)" && cd dist && tar uf $*-src.tar --mtime="$${mtime}" --mode=664 --owner=root --group=root $*/version.make ) - rm dist/$*/version.make + ( mtime="$$(git --git-dir=${SRC_DIR}/.git log -n1 --pretty=%ci)" && cd dist && tar uf $*-src.tar --mtime="$${mtime}" --mode=664 --owner=root --group=root $*/version.mk ) + rm dist/$*/version.mk rmdir dist/$*/ dist/%-attoconf-only.tar: $(MKDIR_FIRST) @@ -11,7 +11,7 @@ The rest of this file contains information relevant to distributors and contribu ## 1. Distributors ### Important notes -- Please read [version.make](version.make) for important version information. +- Please read [version.mk](version.mk) for important version information. - TMWA requires git to build by default. Use 'make dist' to get a tarball. ### Platform dependencies @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2013 Ben Longbons <b.r.longbons@gmail.com> # @@ -17,8 +17,6 @@ # You should have received a copy of the GNU General Public License # along with attoconf. If not, see <http://www.gnu.org/licenses/>. -from __future__ import print_function, division, absolute_import - import os import sys @@ -90,7 +88,7 @@ class Configuration(Cxx, Install, ConfigHash, Templates): # 2) Modern distros ship gtest-1.13+. It requires C++14+, while # TMWA is currently a C++0x codebase. self.add_option('GTEST_DIR', - init=os.path.join(os.getcwd(), 'deps/googletest/googletest'), + init=os.path.join(os.path.abspath(self.srcdir), 'deps/googletest/googletest'), # http://code.google.com/p/googletest/wiki/FAQ#Why_is_it_not_recommended_to_install_a_pre-compiled_copy_of_Goog type=filepath, check=lambda build, GTEST_DIR: None, help='Location of Google Test sources, must contain src/gtest-all.cc (linking to a precompiled library is NOT supported)', hidden=False) @@ -112,7 +110,9 @@ def main(): srcdir = os.path.dirname(sys.argv[0]) proj = Configuration( srcdir=srcdir, - template_files=['Makefile'], + # Note that src/conf/version.hpp is made later, by Makefile. + # See version.mk (included by Makefile). + template_files=['Makefile', 'src/conf/install.hpp'], ) proj.set_package('tmwa', 'The Mana World (Athena server)'); proj.jiggle() diff --git a/deps/attoconf b/deps/attoconf -Subproject 7b939e7e4ce36e8b62b10025e567f871731cbf4 +Subproject 58e75e5f1271363a48c2a3417a2851d3b145b3f diff --git a/generate.make b/generate.mk index c32ca8d..c32ca8d 100644 --- a/generate.make +++ b/generate.mk diff --git a/src/conf/install.hpp b/src/conf/install.hpp.in index 42fd125..e63164a 100644 --- a/src/conf/install.hpp +++ b/src/conf/install.hpp.in @@ -20,10 +20,9 @@ // just mention "fwd.hpp" to make formatter happy -#include "conf-raw/str-PACKAGESYSCONFDIR.h" -#include "conf-raw/str-PACKAGELOCALSTATEDIR.h" -#include "conf-raw/str-PACKAGEDATADIR.h" - +#define PACKAGESYSCONFDIR "@SYSCONFDIR@/tmwa"_s +#define PACKAGELOCALSTATEDIR "@LOCALSTATEDIR@/tmwa"_s +#define PACKAGEDATADIR "@PACKAGEDATADIR@"_s namespace tmwa { diff --git a/src/conf/version.hpp b/src/conf/version.hpp.in index df8a8b6..126fae2 100644 --- a/src/conf/version.hpp +++ b/src/conf/version.hpp.in @@ -20,20 +20,19 @@ // just mention "fwd.hpp" to make formatter happy -#include "conf-raw/str-VERSION_FULL.h" -#include "conf-raw/str-VERSION_HASH.h" +#define VERSION_FULL "@VERSION_FULL@"_s +#define VERSION_HASH "@VERSION_HASH@"_s -#include "conf-raw/int-VERSION_MAJOR.h" -#include "conf-raw/int-VERSION_MINOR.h" -#include "conf-raw/int-VERSION_PATCH.h" -#include "conf-raw/int-VERSION_DEVEL.h" +#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define VERSION_DEVEL @PROJECT_VERSION_TWEAK@ -#include "conf-raw/str-VENDOR_NAME.h" -#include "conf-raw/int-VENDOR_POINT.h" -#include "conf-raw/str-VENDOR_SOURCE.h" - -#include "conf-raw/str-VERSION_STRING.h" +#define VENDOR_NAME "@VENDOR_NAME@"_s +#define VENDOR_POINT @VENDOR_POINT@ +#define VENDOR_SOURCE "@VENDOR_SOURCE@"_s +#define VERSION_STRING "@VERSION_STRING@"_s namespace tmwa { diff --git a/src/main-gdb-head.py b/src/main-gdb-head.py index a465c97..09e22fe 100644 --- a/src/main-gdb-head.py +++ b/src/main-gdb-head.py @@ -5,7 +5,7 @@ # gdb sticks everything in one scope. # This lets us enumerate what *we* added. -initial_globals = {id(v):v for v in globals().values()} +initial_globals = {id(v):v for v in list(globals().values())} import re diff --git a/src/map/script-parse.py b/src/map/script-parse.py index 199e348..3346b92 100644 --- a/src/map/script-parse.py +++ b/src/map/script-parse.py @@ -106,7 +106,7 @@ class ScriptBuffer(object): code_begin = code['_M_impl']['_M_start'] code_end = code['_M_impl']['_M_finish'] code_size = int(code_end - code_begin) - r = iter(range(code_size)) + r = iter(list(range(code_size))) for i in r: buf = [] for label in labels_dict.get(i, []): diff --git a/src/mmo/version.cpp b/src/mmo/version.cpp index f91b748..c75c25c 100644 --- a/src/mmo/version.cpp +++ b/src/mmo/version.cpp @@ -20,7 +20,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -#include "../conf/version.hpp" +#include "src/conf/version.hpp" #include "../strings/xstring.hpp" diff --git a/src/shared/lib.cpp b/src/shared/lib.cpp index c0a4371..37b2e93 100644 --- a/src/shared/lib.cpp +++ b/src/shared/lib.cpp @@ -18,7 +18,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -#include "../conf/install.hpp" +#include "src/conf/install.hpp" #include "../strings/literal.hpp" #include "../strings/astring.hpp" diff --git a/tools/bs-align b/tools/bs-align index 6582298..0caf649 100755 --- a/tools/bs-align +++ b/tools/bs-align @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- encoding: utf-8 ## bs-align.py - Filter to align trailing line continuations ## diff --git a/tools/colorize b/tools/colorize index ce6f410..205a1bc 100755 --- a/tools/colorize +++ b/tools/colorize @@ -1,6 +1,4 @@ -#!/usr/bin/env python - -from __future__ import print_function +#!/usr/bin/env python3 import os import sys diff --git a/tools/config.py b/tools/config.py index f87fe77..22ece0b 100755 --- a/tools/config.py +++ b/tools/config.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding: utf-8 # config.py - generator for config file parsers @@ -20,8 +20,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from __future__ import print_function - import glob import os @@ -259,7 +257,7 @@ class Group(object): short_cpp_name = '%s.cpp' % var_name cpp_name = os.path.join(path, short_cpp_name) - values = sorted(self.options.values(), key=lambda o: o.name) + values = sorted(list(self.options.values()), key=lambda o: o.name) desc = 'Config for %s::%s' % (namespace_name, self.name) with OpenWrite(hpp_name) as hpp, \ @@ -384,7 +382,7 @@ class Realm(object): return rv def dump(self): - for g in self.groups.values(): + for g in list(self.groups.values()): g.dump_in(self.path, self.path.split('/')[-1]) class Everything(object): @@ -401,7 +399,7 @@ class Everything(object): def dump(self): for g in glob.glob('src/*/*_conf.[ch]pp'): os.rename(g, g + '.old') - for v in self.realms.values(): + for v in list(self.realms.values()): v.dump() for g in glob.glob('src/*/*_conf.[ch]pp.old'): print('Obsolete: %s' % g) diff --git a/tools/debug-debug-scripts b/tools/debug-debug-scripts index 2112a6e..5ba7ecb 100755 --- a/tools/debug-debug-scripts +++ b/tools/debug-debug-scripts @@ -1,6 +1,5 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # encoding: utf-8 -from __future__ import print_function copyright = ''' // Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> @@ -35,6 +34,12 @@ error = False def eprint(s): print('Error:', s, file=sys.stderr) +# Implement an equivalent to Python 2's execfile for Python 3 +def execfile(filename, globals=None, locals=None): + with open(filename, 'r') as f: + code = compile(f.read(), filename, 'exec') + exec(code, globals, locals) + def get_classes_from_file(a): global error d = {} diff --git a/tools/debug-debug.gdb b/tools/debug-debug.gdb index b50a49b..5bf3a57 100644 --- a/tools/debug-debug.gdb +++ b/tools/debug-debug.gdb @@ -9,7 +9,7 @@ gdb.execute('file %s' % file_to_load) end set logging file /dev/null set logging redirect on -set logging off +set logging enabled off python import re @@ -41,7 +41,7 @@ set print elements 9999 set print frame-arguments none set python print-stack full -set logging on +set logging enabled on # Workaround "Function... not defined in.." (breakpoints not found) (GDB bug) # https://sourceware.org/bugzilla/show_bug.cgi?id=15962 # In some gdb versions rbreak works, in some break does. @@ -55,7 +55,7 @@ if bpoint.pending: gdb.execute("rbreak do_breakpoint") end -set logging off +set logging enabled off commands silent diff --git a/tools/indenter b/tools/indenter index 0d93543..ee000da 100755 --- a/tools/indenter +++ b/tools/indenter @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- encoding: utf-8 ## indenter.py - Top-level indenter for all files ## @@ -20,10 +20,9 @@ ## along with this program. If not, see <http://www.gnu.org/licenses/>. -from __future__ import print_function from collections import namedtuple -import cStringIO +import io import string import subprocess import sys @@ -114,7 +113,7 @@ class Reader(object): self._column += 1 def string_reader(s, name='<string>', line=1, column=1): - return Reader(name, cStringIO.StringIO(s), line, column) + return Reader(name, io.StringIO(s), line, column) def take_while(b, r, s): assert isinstance(b, bytearray) diff --git a/tools/pp-indent b/tools/pp-indent index 9be9a03..622614a 100755 --- a/tools/pp-indent +++ b/tools/pp-indent @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- encoding: utf-8 ## pp-indent - Filter to apply indentation to preprocessor statements ## diff --git a/tools/protocol.py b/tools/protocol.py index cf89a16..c4c8657 100755 --- a/tools/protocol.py +++ b/tools/protocol.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding: utf-8 # protocol.py - generator for entire TMWA network protocol @@ -20,8 +20,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from __future__ import print_function - import glob import itertools import os @@ -29,11 +27,6 @@ from pipes import quote from posixpath import relpath from weakref import ref as wr -try: - unicode -except NameError: - unicode = str - ## For various reasons this is all one file, so let's navigate with a ## ## Table of Contents @@ -91,7 +84,7 @@ class OpenWrite(object): self.filename = filename def __enter__(self): - self.handle = open(self.filename + '.tmp', 'w') + self.handle = open(self.filename + '.tmp', 'w', encoding='utf-8') return self.handle def __exit__(self, ty, v, tb): @@ -116,30 +109,30 @@ class OpenWrite(object): # TOC_ def gvq(s): - return u'"%s"' % s.replace(u'"', u'\\"') + return '"%s"' % s.replace('"', '\\"') def gva(d): if d: - return u' [%s]' % u', '.join(u'%s=%s' % (ak, gvq(av)) for (ak, av) in sorted(d.items())) - return u'' + return ' [%s]' % ', '.join('%s=%s' % (ak, gvq(av)) for (ak, av) in sorted(d.items())) + return '' class Attributes(object): - __slots__ = (u'_attributes') + __slots__ = ('_attributes') def __init__(self): self._attributes = {} def __getitem__(self, k): - assert isinstance(k, unicode) + assert isinstance(k, str) return self._attributes[k] def __setitem__(self, k, v): - assert isinstance(k, unicode) - assert isinstance(v, unicode) + assert isinstance(k, str) + assert isinstance(v, str) self._attributes[k] = v def __delitem__(self, k): - assert isinstance(k, unicode) + assert isinstance(k, str) del self._attributes[k] def merge(self, *others): @@ -150,7 +143,7 @@ class Attributes(object): self._attributes.update(other._attributes) class Graph(Attributes): - __slots__ = (u'default_vertex', u'default_edge', u'_vertices', u'_edges', u'_vertex_lookup') + __slots__ = ('default_vertex', 'default_edge', '_vertices', '_edges', '_vertex_lookup') def __init__(self): Attributes.__init__(self) @@ -161,7 +154,7 @@ class Graph(Attributes): self._vertex_lookup = {} def vertex(self, name, insert=True): - assert isinstance(name, unicode) + assert isinstance(name, str) vert = self._vertex_lookup.get(name) if insert and vert is None: vert = Vertex(name) @@ -238,21 +231,21 @@ class Graph(Attributes): def p(*args): for x in args: - out.write(unicode(x)) - out.write(u'\n') - p(u'digraph') - p(u'{') + out.write(str(x)) + out.write('\n') + p('digraph') + p('{') for ak, av in sorted(self._attributes.items()): - p(u' ', ak, u'=', gvq(av), u';') + p(' ', ak, '=', gvq(av), ';') for ak, av in sorted(self.default_vertex._attributes.items()): - p(u' node [', ak, u'=', gvq(av), u'];') + p(' node [', ak, '=', gvq(av), '];') for ak, av in sorted(self.default_edge._attributes.items()): - p(u' edge [', ak, u'=', gvq(av), u'];') + p(' edge [', ak, '=', gvq(av), '];') for n in sorted(self._vertices): - p(u' ', n) + p(' ', n) for _, e in sorted(self._edges.items()): - p(u' ', e) - p(u'}') + p(' ', e) + p('}') def dot_str(self): from io import StringIO @@ -261,18 +254,18 @@ class Graph(Attributes): return out.getvalue() def dot_file(self, name): - with open(name, u'w') as f: + with open(name, 'w') as f: self.dot(f, False) def preview(self, block): from subprocess import Popen, PIPE - proc = Popen([u'dot', u'-Txlib', u'/dev/stdin'], stdin=PIPE, universal_newlines=True) + proc = Popen(['dot', '-Txlib', '/dev/stdin'], stdin=PIPE, universal_newlines=True) self.dot(proc.stdin, True) if block: proc.wait() class Vertex(Attributes): - __slots__ = (u'_key', u'_post', u'_pre', u'__weakref__') + __slots__ = ('_key', '_post', '_pre', '__weakref__') def __init__(self, key): Attributes.__init__(self) @@ -281,13 +274,13 @@ class Vertex(Attributes): self._pre = set() def __str__(self): - return u'%s%s;' % (gvq(self._key), gva(self._attributes)) + return '%s%s;' % (gvq(self._key), gva(self._attributes)) def __lt__(self, other): return self._key < other._key class Edge(Attributes): - __slots__ = (u'_from', u'_to') + __slots__ = ('_from', '_to') def __init__(self, f, t): Attributes.__init__(self) @@ -295,7 +288,7 @@ class Edge(Attributes): self._to = t def __str__(self): - return u'%s -> %s%s;' % (gvq(self._from._key), gvq(self._to._key), gva(self._attributes)) + return '%s -> %s%s;' % (gvq(self._from._key), gvq(self._to._key), gva(self._attributes)) # TOC_TYPES @@ -7091,7 +7084,7 @@ def partition(d): changed = True while changed: changed = False - for k, vlist in d.items(): + for k, vlist in list(d.items()): if vlist: m = min(leaders[v] for v in vlist) if m < leaders[k]: @@ -7107,9 +7100,9 @@ def partition(d): leaders[v] = m followers = {} - for k, v in leaders.items(): + for k, v in list(leaders.items()): followers.setdefault(v, []).append(k) - return [set(v) for v in followers.values()] + return [set(v) for v in list(followers.values())] def ids_only(vpost): rv = [e for e in vpost if not isinstance(e, SpecialEventOrigin)] @@ -7124,7 +7117,7 @@ def make_dots(ctx): #p = partition({k: ids_only(v.post) for (k, v) in d.items()}) if not os.path.exists('doc-gen'): - # generate.make will succeed if missing the wiki repo + # generate.mk will succeed if missing the wiki repo # but 'make doc' will fail return for g in glob.glob('doc-gen/*.gv'): @@ -7132,7 +7125,7 @@ def make_dots(ctx): for g in glob.glob('doc-gen/Packet-*.md'): os.rename(g, g + '.old') - for (id, p) in d.items(): + for (id, p) in list(d.items()): md = 'doc-gen/Packet-0x%04x.md' % id dot = 'doc-gen/packets-around-0x%04x.gv' % id with OpenWrite(md) as f: @@ -7179,16 +7172,16 @@ def make_dots(ctx): covered_nodes = sorted(p.pre_set(d, 2) | p.post_set(d, 2)) covered_edges = [(a, b) for a in covered_nodes for b in covered_nodes if b in d[a].post] g = Graph() - g.default_vertex[u'shape'] = u'box' - # g[u'layout'] = u'twopi' - # g[u'root'] = u'0x%04x' % id + g.default_vertex['shape'] = 'box' + # g['layout'] = 'twopi' + # g['root'] = '0x%04x' % id for n in covered_nodes: - v = g.vertex(u'0x%04x' % n) - v[u'label'] = u'Packet \\N: %s' % d[n].name + v = g.vertex('0x%04x' % n) + v['label'] = 'Packet \\N: %s' % d[n].name if n == id: - v[u'style'] = u'filled' + v['style'] = 'filled' for (a, b) in covered_edges: - g.edge(u'0x%04x' % a, u'0x%04x' % b) + g.edge('0x%04x' % a, '0x%04x' % b) for n in covered_nodes: # the center node will be covered specially below if n == id: @@ -7206,10 +7199,10 @@ def make_dots(ctx): # don't show mere siblings unless also ancestor/descendent count += 1 if count: - v = g.vertex(u'0x%04x...pre' % n) - v[u'label'] = u'%d more' % count - v[u'style'] = u'dashed' - g.edge(v, u'0x%04x' % n) + v = g.vertex('0x%04x...pre' % n) + v['label'] = '%d more' % count + v['style'] = 'dashed' + g.edge(v, '0x%04x' % n) # strong forward links count = 0 for p in d[n].post: @@ -7218,36 +7211,36 @@ def make_dots(ctx): elif p not in covered_nodes: count += 1 if count: - v = g.vertex(u'0x%04x...post' % n) - v[u'label'] = u'%d more' % count - v[u'style'] = u'dashed' - g.edge(u'0x%04x' % n, v) + v = g.vertex('0x%04x...post' % n) + v['label'] = '%d more' % count + v['style'] = 'dashed' + g.edge('0x%04x' % n, v) # for the immediate node, also cover specials and weaks for p in d[id].pre: # (there are no weak backward specials) # strong backward specials if isinstance(p, SpecialEventOrigin): - g.edge(unicode(p.name), u'0x%04x' % id) + g.edge(str(p.name), '0x%04x' % id) # weak backward nodes elif id in d[p].xpost: - e = g.edge(u'0x%04x' % p, u'0x%04x' % id) - e[u'style']=u'dashed' - e[u'weight'] = u'0' + e = g.edge('0x%04x' % p, '0x%04x' % id) + e['style']='dashed' + e['weight'] = '0' for p in d[id].post: # strong forward specials if isinstance(p, SpecialEventOrigin): - g.edge(u'0x%04x' % id, unicode(p.name)) + g.edge('0x%04x' % id, str(p.name)) for p in d[id].xpost: # weak forward specials if isinstance(p, SpecialEventOrigin): - e = g.edge(u'0x%04x' % id, unicode(p.name)) - e[u'style'] = u'dashed' - e[u'weight'] = u'0' + e = g.edge('0x%04x' % id, str(p.name)) + e['style'] = 'dashed' + e['weight'] = '0' # weak forward nodes elif p not in covered_nodes: - e = g.edge(u'0x%04x' % id, u'0x%04x' % p) - e[u'style'] = u'dashed' - e[u'weight'] = u'0' + e = g.edge('0x%04x' % id, '0x%04x' % p) + e['style'] = 'dashed' + e['weight'] = '0' g.dot(f, False) diff --git a/version.make b/version.mk index 73ecc83..23bd071 100644 --- a/version.make +++ b/version.mk @@ -39,7 +39,7 @@ VENDOR_NAME := Vanilla VENDOR_POINT := 0 # URL where the source may be found (after searching for version number). # See AGPLv3 section 13 -VENDOR_SOURCE := https://github.com/themanaworld/tmwa +VENDOR_SOURCE := https://git.themanaworld.org/legacy/tmwa # Convenience VERSION_STRING := TMWA ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH} dev${VERSION_DEVEL} +${VENDOR_POINT} (${VENDOR_NAME}) @@ -50,9 +50,38 @@ SO_SHORT := so.${ABI_VERSION} SO_LONG := ${SO_SHORT}.${VERSION_DOTS} # and thanks for all the fish +# This is a phony target, so that it always runs. +# Targets which depend on this will always have their recipes run. +FORCE:: ; +.PHONY: FORCE + +# Fully generate version.hpp here, where we have all the relevant information. +# version.mk is included by the top level Makefile, so simply explaning how to +# make it here will let it be built later, when needed. +# Note that some variable substitutions are slightly different here to use the +# name used by standard CMake macros, such as PROJECT_VERSION_TWEAK instead of +# VERSION_DEVEL. +src/conf/version.hpp: src/conf/version.hpp.in FORCE + sed -e 's/@VERSION_FULL@/${VERSION_FULL}/g' \ + -e 's/@VERSION_HASH@/${VERSION_HASH}/g' \ + -e 's/@VERSION_STRING@/${VERSION_STRING}/g' \ + -e 's/@PROJECT_VERSION_MAJOR@/${VERSION_MAJOR}/g' \ + -e 's/@PROJECT_VERSION_MINOR@/${VERSION_MINOR}/g' \ + -e 's/@PROJECT_VERSION_PATCH@/${VERSION_PATCH}/g' \ + -e 's/@PROJECT_VERSION_TWEAK@/${VERSION_DEVEL}/g' \ + -e 's/@VENDOR_NAME@/${VENDOR_NAME}/g' \ + -e 's/@VENDOR_POINT@/${VENDOR_POINT}/g' \ + -e 's|@VENDOR_SOURCE@|${VENDOR_SOURCE}|g' \ + -e 's/@ABI_VERSION@/${ABI_VERSION}/g' \ + -e 's/@SO_SHORT@/${SO_SHORT}/g' \ + -e 's/@SO_LONG@/${SO_LONG}/g' \ + $< > $@ + + version: @echo version '${VERSION_STRING}' @echo based on commit ${VERSION_FULL} aka ${VERSION_HASH} @echo source ${VENDOR_SOURCE} @echo abi version ${ABI_VERSION} @echo 'lib so -> ${SO_SHORT} -> ${SO_LONG}' +.PHONY: version |