Skip to content

Commit 9675405

Browse files
committed
Makefile.am, CMake: simplify bootstrap process.
Re2c is a self-hosting lexer generator, therefore it needs re2c in order to rebuild itself. It bootstraps using precompiled files in the bootstrap subdirectory. Precompiled files can be used as long as the .re files are not changed, otherwise lexers must be regenerated. Previosuly the build system tried to autodetect whether to regenerate or to copy bootstrap files by checking if the re2c executable exists in the build directory. However, for the build system it means that dependency graph is changed on every build, because bootstrap commands and regenerate commands have different dependencies: bootstrap commands depend on the bootstrap files, and regenerate commands depend on the .re files. It is not possible to choose the commands statically, because the check for re2c executable should run on every build rather than once at configure time. CMake used a workaround and set both bootstrap and .re files as dependencies for both commands, which caused weird rebuilds on Travis CI (when the same lexer was regenerated multiple times during one build). Automake used a different workaround (a pattern rule that didn't have the dependency on bootstrap files at all). This commit disables the checking mechanism and requires passing an explicit configure parameter and a path to the re2c executable in order to regenerate lexers. Otherwise, by default lexers are copied from bootstrap files. CMake: cmake ... -DRE2C_REBUILD_LEXERS=on -DRE2C_FOR_BUILD=<path> Makefile.am: configure ... --enable-lexers RE2C_FOR_BUILD=<path>
1 parent f025279 commit 9675405

4 files changed

Lines changed: 87 additions & 60 deletions

File tree

CMakeLists.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ include(Re2cTryCXXFlag)
1010

1111
ac_subst(PACKAGE_VERSION "${PROJECT_VERSION}")
1212

13+
option(RE2C_REBUILD_LEXERS "Regenerate lexers" OFF)
14+
if(RE2C_REBUILD_LEXERS AND NOT RE2C_FOR_BUILD)
15+
message(FATAL_ERROR "need RE2C_FOR_BUILD for RE2C_REBUILD_LEXERS")
16+
endif()
17+
1318
option(RE2C_REBUILD_DOCS "Regenerate manpage" OFF)
14-
if (RE2C_REBUILD_DOCS)
19+
if(RE2C_REBUILD_DOCS)
1520
find_program(RST2MAN NAMES rst2man rst2man.py)
16-
if (NOT RST2MAN)
17-
message(FATAL_ERROR "need rst2man or rst2man.py for RE2C_REBUILD_DOCS=YES")
21+
if(NOT RST2MAN)
22+
message(FATAL_ERROR "need rst2man or rst2man.py for RE2C_REBUILD_DOCS")
1823
endif()
1924
endif()
2025

Makefile.am

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ if DEBUG
99
AM_CXXFLAGS += -DRE2C_DEBUG
1010
endif
1111

12-
RE2CFLAGS = -br -W
12+
RE2CFLAGS = -br -W -Wno-match-empty-string
1313

1414
# binary
1515
bin_PROGRAMS = re2c
1616
noinst_PROGRAMS =
17-
RE2C = re2c$(EXEEXT)
1817

1918
# sources
2019
re2c_HDR = \
@@ -310,26 +309,35 @@ CLEANFILES = \
310309
$(re2c_GEN) \
311310
$(DOCS)
312311

312+
if REBUILD_LEXERS
313+
# generate lexer and update bootstrap files
313314
.re.cc:
314315
$(AM_V_at)$(MKDIR_P) $(@D)
315-
$(AM_V_GEN) if test -x $(RE2C); \
316+
$(AM_V_GEN)if test -x $(RE2C_FOR_BUILD); \
316317
then \
317-
$(top_builddir)/$(RE2C) $(RE2CFLAGS) -o $@ $< && \
318+
$(RE2C_FOR_BUILD) $(RE2CFLAGS) -o $@ $< && \
318319
cp $(@:cc=[ch]*) $(top_srcdir)/bootstrap/$(@D); \
319320
else \
320-
cp $(top_srcdir)/bootstrap/$(@:cc=*) $(@D); \
321+
echo "RE2C is not an executable file" && exit 1 ; \
321322
fi
323+
else
324+
# copy bootstrap files
325+
.re.cc:
326+
$(AM_V_at)$(MKDIR_P) $(@D)
327+
$(AM_V_GEN)cp $(top_srcdir)/bootstrap/$(@:cc=*) $(@D)
328+
$(AM_V_at)echo "Reconfigure with --enable-lexers to regenerate $@"
329+
endif
322330

323331
# cannot update bootstrap with distcheck (it makes srcdir readonly),
324332
# so we update bootstrap only on incremental build (if re2c binary exists)
325333
.ypp.cc:
326334
$(AM_V_at)$(MKDIR_P) $(@D)
327-
$(AM_V_GEN) if test $(BISON) = "no"; \
335+
$(AM_V_GEN)if test $(BISON) = "no"; \
328336
then \
329337
cp $(top_srcdir)/bootstrap/$(@:cc=*) $(@D); \
330338
else \
331339
$(BISON) --output=$@ --defines=$(@:cc=h) $< && \
332-
if test -x $(RE2C); then \
340+
if test -x $(top_builddir)/re2c$(EXEEXT); then \
333341
cp $@ $(@:cc=h) $(top_srcdir)/bootstrap/$(@D); \
334342
fi; \
335343
fi
@@ -371,7 +379,7 @@ $(re2c_GEN_HELP): $(re2c_CUSTOM_HELP) $(GENHELP)
371379
&& rm $@.1
372380
else
373381
docs: $(DOCS) $(re2c_GEN_HELP)
374-
$(AM_V_at)echo "Reconfigure to rebuild docs: ./configure --enable-docs"
382+
$(AM_V_at)echo "Reconfigure with --enable-docs to rebuild docs"
375383
# copy bootstrap manpage for C
376384
$(DOC_C): $(re2c_BOOT_DOC_C)
377385
$(AM_V_at)$(MKDIR_P) $(@D)

cmake/Re2cBootstrapLexer.cmake

Lines changed: 52 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,58 @@
1-
if (CMAKE_CURRENT_LIST_FILE STREQUAL CMAKE_SCRIPT_MODE_FILE)
2-
get_filename_component(parent_dir "${cc_file}" DIRECTORY)
3-
file(RELATIVE_PATH relative_re_file "${CMAKE_CURRENT_BINARY_DIR}" "${source_dir}/${re_file}")
1+
function(re2c_bootstrap_lexer input output)
2+
# optional header file, 3rd argument
3+
set(header "${ARGN}")
44

5-
file(MAKE_DIRECTORY "${parent_dir}")
6-
if (EXISTS "${re2c}")
7-
execute_process(
8-
COMMAND "${re2c}" -br -W "${relative_re_file}" -o "${cc_file}"
9-
RESULT_VARIABLE ret
10-
)
11-
if (NOT ret EQUAL 0)
12-
message(FATAL_ERROR "Failure running re2c: got exit status ${ret}")
13-
endif()
14-
file(COPY "${cc_file}" DESTINATION "${source_dir}/bootstrap/${parent_dir}")
15-
if (NOT "${h_file}" STREQUAL "")
16-
file(COPY "${h_file}" DESTINATION "${source_dir}/bootstrap/${parent_dir}")
17-
endif()
18-
else()
19-
file(COPY "${source_dir}/bootstrap/${cc_file}" DESTINATION "${parent_dir}")
20-
if (NOT "${h_file}" STREQUAL "")
21-
file(COPY "${source_dir}/bootstrap/${h_file}" DESTINATION "${parent_dir}")
22-
endif()
23-
endif()
5+
# source files (use relative path to avoid hardcoding in line directives)
6+
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${input}")
7+
file(RELATIVE_PATH relative_source "${CMAKE_CURRENT_BINARY_DIR}" "${source}")
248

25-
return()
26-
endif()
9+
# bootstrap files
10+
set(boot_output "${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/${output}")
11+
set(boot_header "${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/${header}")
2712

28-
set(__re2c_bootstrap_lexer_cmake "${CMAKE_CURRENT_LIST_FILE}")
13+
set(re2c_flags "-br" "-W" "-Wno-match-empty-string")
2914

30-
function(re2c_bootstrap_lexer re_file cc_file)
31-
set(h_file "${ARGN}")
32-
set(outputs)
33-
list(APPEND outputs "${cc_file}")
34-
if(h_file)
35-
list(APPEND outputs "${h_file}")
36-
endif()
37-
if(NOT TARGET re2c)
38-
message(FATAL_ERROR "'re2c' is not a valid target")
15+
if (RE2C_REBUILD_LEXERS)
16+
# recompile the lexer and update bootstrap file(s)
17+
if("${header}" STREQUAL "")
18+
# without header
19+
add_custom_command(
20+
OUTPUT "${output}"
21+
COMMAND "${RE2C_FOR_BUILD}" ${re2c_flags} "${relative_source}" -o "${output}"
22+
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${output}" "${boot_output}"
23+
DEPENDS "${source}"
24+
COMMENT "Generating ${output}"
25+
)
26+
else()
27+
# with header
28+
add_custom_command(
29+
OUTPUT "${output}" "${header}"
30+
COMMAND "${RE2C_FOR_BUILD}" ${re2c_flags} "${relative_source}" -o "${output}"
31+
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${output}" "${boot_output}"
32+
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${header}" "${boot_header}"
33+
DEPENDS "${source}"
34+
COMMENT "Generating ${output} and ${header}"
35+
)
36+
endif()
37+
else()
38+
# copy precompiled bootstrap file(s)
39+
if("${header}" STREQUAL "")
40+
# without header
41+
add_custom_command(
42+
OUTPUT "${output}"
43+
COMMAND "${CMAKE_COMMAND}" -E copy "${boot_output}" "${output}"
44+
DEPENDS "${source}" "${boot_output}"
45+
COMMENT "Copying bootstrap ${output}, reconfigure with RE2C_REBUILD_LEXERS to regenerate"
46+
)
47+
else()
48+
# with header
49+
add_custom_command(
50+
OUTPUT "${output}" "${header}"
51+
COMMAND "${CMAKE_COMMAND}" -E copy "${boot_output}" "${output}"
52+
COMMAND "${CMAKE_COMMAND}" -E copy "${boot_header}" "${header}"
53+
DEPENDS "${source}" "${boot_output}" "${boot_header}"
54+
COMMENT "Copying bootstrap ${output} and ${header}, reconfigure with RE2C_REBUILD_LEXERS to regenerate"
55+
)
56+
endif()
3957
endif()
40-
add_custom_command(
41-
OUTPUT ${outputs}
42-
COMMAND
43-
"${CMAKE_COMMAND}"
44-
-Dsource_dir="${CMAKE_CURRENT_SOURCE_DIR}"
45-
-Dre_file="${re_file}" -Dcc_file="${cc_file}" -Dh_file="${h_file}"
46-
# Avoid $<TARGET_FILE:re2c>, because that adds a dependency on re2c,
47-
# which causes CMake to error if we put this into an object library,
48-
# which we need to have libre2c built from bootstrap too
49-
-Dre2c="${CMAKE_CURRENT_BINARY_DIR}/re2c${CMAKE_EXECUTABLE_SUFFIX}"
50-
-P "${__re2c_bootstrap_lexer_cmake}"
51-
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
52-
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/${re_file}"
53-
DEPENDS "${__re2c_bootstrap_lexer_cmake}"
54-
)
5558
endfunction()

configure.ac

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ AM_COND_IF([REBUILD_DOCS], [
3535
])
3636

3737

38+
# --enable-lexers
39+
AC_ARG_ENABLE([lexers], [AS_HELP_STRING([--enable-lexers], [regenerate lexers])])
40+
AM_CONDITIONAL([REBUILD_LEXERS], [test "x$enable_lexers" = "xyes"])
41+
AM_COND_IF([REBUILD_LEXERS], [
42+
AC_ARG_VAR(RE2C_FOR_BUILD, re2c executable used to regenerate lexers)
43+
AS_IF([test ! -x "$RE2C_FOR_BUILD"], [
44+
AC_MSG_ERROR([RE2C_FOR_BUILD must be set to an executable file with --enable-lexers])
45+
])
46+
])
47+
48+
3849
# --enable-libs
3950
AC_ARG_ENABLE([libs], [AS_HELP_STRING([--enable-libs], [build libraries])])
4051
AM_CONDITIONAL([WITH_LIBS], [test "x$enable_libs" = "xyes"])

0 commit comments

Comments
 (0)