-
-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better support building the runtime separately #4743
Conversation
It looks like cmake is not adding the dependency on |
I've reduced it to: cmake_minimum_required(VERSION 3.27)
project("compiler" LANGUAGES CXX)
set(full "${PROJECT_BINARY_DIR}/bin/mycompiler")
if(TRUE)
# fails
add_custom_command(OUTPUT "${full}"
COMMAND g++ -o "${full}" "${PROJECT_SOURCE_DIR}/mycompiler.cpp"
DEPENDS mycompiler.cpp
)
add_custom_target(mycompiler ALL DEPENDS "${full}")
else()
# works
add_executable(mycompiler "mycompiler.cpp")
set_target_properties(mycompiler PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
endif()
add_custom_command(OUTPUT foo.o
COMMAND "${full}" -o foo.o foo.cpp
DEPENDS mycompiler
DEPENDS_EXPLICIT_ONLY # this thing breaks
)
add_library(foo STATIC foo.o)
set_target_properties(foo PROPERTIES LINKER_LANGUAGE CXX)
|
This seems to be the intended behavior. From add_custom_command docs:
This wording clearly states that the dependency of What we need:
What cmake does:
Since this seems to be the intended behavior the |
8f1bfff
to
3e4441d
Compare
Are you aware of https://wiki.dlang.org/Building_LDC_runtime_libraries? The |
I was aware of the tool and the fact that it was mostly a wrapper over cmake so I would prefer to use cmake directly. When I first tried to build the runtime for multilib directly the building itself worked but I hit an issue with the test runners and the druntime integration tests. I think I tried to do The only thing that doesn't work are the druntime integration tests so we either have pass As a conclusion, is it fine if to keep the non-flag related changes like the addition of |
I can also improve the code and add support for |
My insistence on allowing It's also more clear which arguments are required, otherwise the compilation will fail (or do the wrong thing), and which arguments are optional, passed by the user for a more efficient/safe/whatever they desire final binary. In the latter case it's safe to ignore those flags if we're building some intermediary object that we may need for running the tests / generating documentation so we don't always need to respect them. I'm saying all this not to convince you, but for you to know what my position on the matter is. I won't keep pushing for such changes unless the current |
Yeah I guessed you were after the druntime integration tests, which as you figured, are currently only run for the primary platform. If we wanted to include the 32-bit druntime integration tests for MULTILIB builds, we'd need to add some test name suffix to make them unique.
What I don't like is that we already have a variable for extra flags, and having to take account cmdline options in a compiler var. I trust this is some common concept on Posix, but I don't really like that extra cognitive overhead and CMake special cases. Maybe coz I grew up with Windows, where such space-separated flags are unthinkable. ;) |
3e4441d
to
c788ab2
Compare
The druntime test makefiles already support
Yeah, I can see why you wouldn't want your |
For custom commands that require a built ldc2 specify only an absolute path to compiler binary, not the target name. This is because cmake handles file paths and target dependencies differently. In the case of a target dependency the dependency doesn't actually apply to the `add_custom_command`, it only affects future targets. As an example, we want to built libruntime.a from a D file foo.d. What we need to describe is: 1. compile foo.o from foo.d (depends on LDC) 2. archive libruntime.a from foo.o If we use ${LDC_EXE} as a dependency (only the target name) cmake would generate: 1. compile foo.o from foo.d 2. archive libruntime.a from foo.o (depends on LDC) Using an absolute path for the LDC dependency does what we want it to do. Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
D_EXTRA_FLAGS is the intended way to pass flags like -m32 to ldc so make sure that its value is respected during the druntime tests. Signed-off-by: Andrei Horodniceanu <a.horodniceanu@proton.me>
c788ab2
to
0dcf778
Compare
-set(LDMD_CMD "${LDMD_EXE_FULL} ${D_EXTRA_ARGS}")
+string(REPLACE ";" " " LDMD_CMD "${LDMD_EXE_FULL} ${D_EXTRA_FLAGS}")
|
set(dc_deps ${LDC_EXE} ${LDC_EXE_FULL} ${GCCBUILTINS}) | ||
# dc_deps can only contain paths, otherwise cmake will ignore the dependency. | ||
# See: https://github.com/ldc-developers/ldc/pull/4743#issuecomment-2323156173 | ||
set(dc_deps ${LDC_EXE_FULL} ${GCCBUILTINS}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yet we add a add-multilib-section
target name 3 lines below. According to
If the argument is the name of a target (created by the add_custom_target(), add_executable(), or add_library() command) a target-level dependency is created to make sure the target is built before any target using this custom command.
this should still make sure the target is created before building any dependent. The (additional) path dependency should take care of the 2nd part wrt. rebuilds IIUC:
Additionally, if the target is an executable or library, a file-level dependency is created to cause the custom command to re-run whenever the target is recompiled.
I guess they actually mean 'if the target is an add_executable or add_library target', so that one has to specify the path to the add_custom_target
executable manually for proper rebuilds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yet we add a
add-multilib-section
target name 3 lines below. According to
If the argument is the name of a target (created by the add_custom_target(), add_executable(), or add_library() command) a target-level dependency is created to make sure the target is built before any target using this custom command.
this should still make sure the target is created before building any dependent. The (additional) path dependency should take care of the 2nd part wrt. rebuilds IIUC:
From looking at build.ninja
, the add-multilib-section
target is added as a dependency to the final libraries, like lib64/libdruntime-ldc-shared.so.109.1
. I think this is fine, as the libraries are compiled with -conf=
so they don't actually need the config file to be updated. In this case I think the weird cmake behavior does what we want: "update the config file before declaring the library built", it just does it a little bit later in the process.
Additionally, if the target is an executable or library, a file-level dependency is created to cause the custom command to re-run whenever the target is recompiled.
I guess they actually mean 'if the target is an add_executable or add_library target', so that one has to specify the path to the
add_custom_target
executable manually for proper rebuilds.
I'm reading this the other way around:
- if the target is an executable or library, cmake adds a file-path dependency automatically => we don't need to specify a full path as a dependency.
- otherwise, cmake does nothing => we need to specify the full path if we need that dependency to be built before this
add_custom_command
oradd_custom_target
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess they actually mean 'if the target is an add_executable or add_library target', so that one has to specify the path to the add_custom_target executable manually for proper rebuilds.
I'm reading this the other way around:
I'm pretty sure the 'target' they refer to is the dependency being added, i.e., LDC_EXE
(expands to ldc2
) here. Which can either be an add_executable
or an add_custom_target
, depending on LDC_LINK_MANUALLY
. So in case the ldc2 executable is a custom target, we additionally add LDC_EXE_FULL
so that the runtimes stuff is rebuilt whenever the compiler is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes, I understand it the same way. Maybe I failed to word it right but, in my defense, it is a unintuitive behavior cmake is exhibiting.
... so that the runtimes stuff is rebuilt whenever the compiler is.
- that the compiler is built, if not present, before the runtime build commands try to invoke it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully agreed wrt. unintuitive (edit: and bad wording on my part - the compiler file dependency via LDC_EXE_PATH should make sure existing runtime build artifacts get stale as soon as the compiler is rebuilt). Probably related: we had CI issues with the make
backend, IIRC some targets not waiting for the prerequisites to be finished. Working fine with ninja
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay after another re-read, I think I got your point now - that the LDC_EXE
target name dependency does NOT apply to the custom command getting this dependency directly, but only to the dependents of that custom command. So you're absolutely right, the target-name dependency is insufficient, we need the path dependency to make it apply to the custom command directly, and not just for rebuilds. Thanks for digging!
@@ -56,6 +56,8 @@ else() | |||
list(REMOVE_ITEM testnames uuid) | |||
endif() | |||
|
|||
string(REPLACE ";" " " LDMD_CMD "${LDMD_EXE_FULL} ${D_EXTRA_FLAGS}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your use case would be setting D_EXTRA_FLAGS=-m32
, right? Just to understand. This step should probably be skipped on Windows [but that divergence would be a bit ugly IMO], to avoid spaces in the path and spaces as flag separators.
AFAICT, the multilib case would be designed to be used with the MODEL make variable:
ldc/runtime/druntime/test/common.mak
Line 33 in 1f0c36e
MODEL_FLAG:=$(if $(findstring $(MODEL),default),,-m$(MODEL)) |
The MODEL would make it into DFLAGS:
ldc/runtime/druntime/test/common.mak
Line 41 in 1f0c36e
DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib=$(if $(findstring ldmd2,$(DMD)),druntime-ldc,) -preview=dip1000 $(if $(findstring $(OS),windows),,-L-lpthread -L-lm $(LINKDL)) |
and CFLAGS_BASE (which we override for non-MSVC targets via CMake cflags_base
though):
ldc/runtime/druntime/test/common.mak
Line 34 in 1f0c36e
CFLAGS_BASE:=$(if $(findstring $(OS),windows),/Wall,$(MODEL_FLAG) $(PIC) -Wall) |
How do you currently handle the C side for the separate 32-bit build? Setting a CC env var incl. an -m32
flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your use case would be setting
D_EXTRA_FLAGS=-m32
, right? Just to understand. This step should probably be skipped on Windows [but that divergence would be a bit ugly IMO], to avoid spaces in the path and spaces as flag separators.
Yes, only -m32
for now. Though it is technically possible, in some future, for this to use other -m<abi>
flags for different architectures.
AFAICT, the multilib case would be designed to be used with the MODEL make variable:
ldc/runtime/druntime/test/common.mak
Line 33 in 1f0c36e
MODEL_FLAG:=$(if $(findstring $(MODEL),default),,-m$(MODEL)) The MODEL would make it into DFLAGS:
ldc/runtime/druntime/test/common.mak
Line 41 in 1f0c36e
DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib=$(if $(findstring ldmd2,$(DMD)),druntime-ldc,) -preview=dip1000 $(if $(findstring $(OS),windows),,-L-lpthread -L-lm $(LINKDL)) and CFLAGS_BASE (which we override for non-MSVC targets via CMake
cflags_base
though):ldc/runtime/druntime/test/common.mak
Line 34 in 1f0c36e
CFLAGS_BASE:=$(if $(findstring $(OS),windows),/Wall,$(MODEL_FLAG) $(PIC) -Wall) How do you currently handle the C side for the separate 32-bit build? Setting a CC env var incl. an
-m32
flag?
These variables are set already by the Gentoo helper functions so I didn't have to interact with them but, if I followed the functions right:
- https://github.com/gentoo/gentoo/blob/e1c6cdf0e713cd916c7880296b3af32834fdb9c0/eclass/multilib.eclass#L544 sets
CC
to contain the-m
flag. - https://github.com/gentoo/gentoo/blob/e1c6cdf0e713cd916c7880296b3af32834fdb9c0/eclass/cmake.eclass#L468-L477 example:
set(CMAKE_C_COMPILER "x86_64-pc-linux-gnu-gcc;-m32 -mfpmath=sse")
Here's what the logs contain:
460: x86_64-pc-linux-gnu-gcc -m32 -mfpmath=sse -Wall -Wl,-rpath,/var/tmp/portage/dev-lang/ldc2-1.40.0_beta3-r1/work/ldc-1.40.0-beta3-src_build-abi_x86_32.x86/lib -L/var/tmp/portage/dev-lang/ldc2-1.40.0_beta3-r1/work/ldc-1.40.0-beta3-src_build-abi_x86_32.x86/lib -O3 -o/var/tmp/portage/dev-lang/ldc2-1.40.0_beta3-r1/work/ldc-1.40.0-beta3-src_build-abi_x86_32.x86/druntime-test-shared-release/linkDR src/linkDR.c /var/tmp/portage/dev-lang/ldc2-1.40.0_beta3-r1/work/ldc-1.40.0-beta3-src_build-abi_x86_32.x86/lib/libdruntime-ldc-shared.so -ldl -pthread
So yeah, setting CC
seems like what's doing the trick, including for the druntime tests that are called through cmake. Note that there isn't a single -m32
flag, -mfpmath=sse
is also present so I would like the solution to allow any combination of flags.
Setting MODEL_FLAG=${D_EXTRA_FLAGS}
seems like it would do the trick:
- allows for arbitrary flags to be passed through
- doesn't interfere with space-splitting
CC
But can you explain something for me? Does gmake
on windows not perform space expansion on variables, regardless of where they appear, or is there some special case only for when the variable appears as the first thing in a command. For example:
main: main.cpp
$(CC) $(CFLAGS) -o main main.cpp
CFLAGS
gets split by spaces. CC
is also split on linux. Does windows not split CC
but splits CFLAGS
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I seem to recall/assume (haven't tested it now!) that on Windows, you are supposed to use explicit quotes, something like make CC="my cc.exe"
. IIRC, make then uses those quotes as-is, so that $(CC) -c
gets expanded to "my cc.exe" -c
. This should allow adding the D_EXTRA_FLAGS to LDMD_CMD
on Windows too. If a poor soul had to split it up into executable and flags, that'd be a PITA of course, as trivial splitting by space wouldn't work of course.
Edit: Tested it; the cmdline needs extra quoting, but the rest holds: make "CC=\"my cc.exe\""
.
Edit2: Nope, make CC="my cc.exe"
also works (in a cmd.exe shell), surprisingly. But that might be some special make behavior on Windows (wrt. the executable part of the command); make "CC=my cc.exe"
also works.
Edit3: With a flag, this would apparently have to be: make "CC=\"my cc.exe\" -abc"
.
Edit4: Oh god, there's definitely some magic logic somewhere, this really works too: make "CC=my cc -abc"
. With a C:\Windows\my cc.exe
(copy of calc.exe ;)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing! I don't have a windows machine so I trust you on these.
So, what's the final solution we go with?
- allow
LDMD_CMD
co contain arguments - use
MODEL_FLAG
to passD_EXTRA_FLAGS
1 is unintutive on windows because of the comamnd magic, 2 is unintuitive everywhere since the variables don't really seem related.
If the tests are adjusted to also test for 32 bit with -DMULTILIB=ON
that would require passing -m32/-m64 somewhere. We could use MODEL
here or just override MODEL_FLAG
again. I think the final result would look like:
1 + MODEL:
# do_druntime_tests invokes the tests with make MODEL=${1}
do_druntime_tests("")
if(MULTILIB)
do_druntime_tests("${HOST_BITNESS}")
endif()
1 + MODEL_FLAG:
# do_druntime_tests invokes the tests with make MODEL_FLAG=${1}
do_druntime_tests("")
if(MULTILIB)
do_druntime_tests("-m${HOST_BITNESS}")
endif()
2 + MODEL_FLAG:
# do_druntime_tests invokes the tests with make MODEL_FLAG="${D_EXTRA_FLAGS} ${1}"
do_druntime_tests("")
if(MULTILIB)
do_druntime_tests("-m${HOST_BITNESS}")
endif()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to, sometime, change the dmd makefiles to allow taking flags from the command line instead of relying on hacks like using MODEL_FLAG, as Gentoo policy dictates it. If I get to upstream these changes we should be able to do make MY_D_FLAGS=${D_EXTRA_FLAGS}
and use either of the model flag logic so maybe it's worth taking this future possibility into consideration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the sake of standardization I would recommend that those variables are, instead, named DFLAGS and CFLAGS as that makes their intent very clear and is the standard way of handling flags.
AFAIK, it's common to have such CFLAGS_BASE, in order to only set optional extra/critical flags on demand. Specifying a make variable like this (after make
, not as env vars) silently skips all regular assignments of CFLAGS_BASE in common.mak
. The full list in CFLAGS etc. can then still be joined together in common.mak
, based on (potentially custom) CFLAGS_BASE.
Similarly, common.mak
currently also allows one to customize CXXFLAGS_BASE
- it just defaults to CFLAGS_BASE
in
ldc/runtime/druntime/test/common.mak
Line 56 in 1f0c36e
CXXFLAGS_BASE:=$(CFLAGS_BASE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if ldc provides simple variables like RT_CFLAGS and RT_LFLAGS to configure its build, on top of working with the flags cmake is configured with, then the easiest way to pass them along to the druntime tests is having the makefile respect variables like DFLAGS_BASE and CFLAGS_BASE just like you suggest.
[The non-super-consistently named CMake variables come from having a fat umbrella CMake build for LDC, where runtime and Phobos are just a subset of all builds. So we ended up with some ugly names for compiler-only D flags, runtime-only D flags etc. etc. They are usually empty, but designed exactly for such target-specific critical flags and/or custom flags.]
In the worst case I would need to add -DRT_CFLAGS=$(get_abi_CFLAGS) which isn't a deal breaker.
The only potential problem I see with you specifying the C flags explicitly this way is that they would be duplicated when building the runtime libraries (due to Gentoo's CMake hook injecting the critical flags), and potentially also for the make integration tests if CC was still set with flags at test-time. The compiler might complain about some options being specified multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only potential problem I see with you specifying the C flags explicitly this way is that they would be duplicated when building the runtime libraries (due to Gentoo's CMake hook injecting the critical flags), and potentially also for the make integration tests if CC was still set with flags at test-time. The compiler might complain about some options being specified multiple times.
I meant that I would pass-DRT_CFLAGS=-m32
if the cmake code were changed to invoke gmake
with CC=${CMAKE_C_COMPILER}
to respect the configure-time value. In that case the environment variable is not in effect so $(CC)
inside make will be the compiler binary without any arguments so there won't be any duplication with RT_CFLAGS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's the case we can handle. But what about the actual library build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, in that case the flags would be duplicated. This shouldn't be an issue and, even if it is, I can always just patch the cmake files to use a separate variable for passing abi-related CFLAGS and only respect in when invoking make, like CC="${CMAKE_C_COMPILER} ${GENTOO_ABI_CFLAGS}"
since this should work on UNIXes.
This is slightly more work for me but, given the choices:
- don't respect ${CMAKE_C_COMPILER} when calling the makefiles and rely on runtime CC
- respect ${CMAKE_C_COMPILER}, even if it discards flags
I would prefer for ldc to use 2, because, if it breaks, it would be easier to diagnose even if that entails me possibly carrying one more patch downstream.
My use case for this is compiling the runtime for x86 on x86_64.
-DMULTILIB=ON
is not sufficient as I need to create a separate project in order to use a system copy of zlib like I've described in #4742 (comment).