Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,34 @@ this file by hand, before proceeding with the build. Note that the the generated
a symbolic link to a system-specific default config file. It is not necessary to edit the file; you
can override variables on the "make" command line if you prefer.

You can also create and edit the "mconfig" file completely by hand (or start by copying one for a
particular OS from the "configs" directory) to choose appropriate values for the configuration
variables defined within.
Comment on lines +39 to +41
Copy link
Owner

Choose a reason for hiding this comment

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

Why are you suggesting this? What's wrong with using "make mconfig" to generate a starting point?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not suggesting that, It was there before (looks like "diff" is misleading in this case):

dinit/BUILD

Lines 47 to 49 in 50cbe18

You can also create and edit the "mconfig" file completely by hand (or start by copying one for a
particular OS from the "configs" directory) to choose appropriate values for the configuration
variables defined within.

Copy link
Owner

Choose a reason for hiding this comment

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

Ok, I see what it is. It came after the small part about configure. You've removed the part about configure completely, shifting it all into a new section, then moved these lines above the section on configure, so they show up as added here and removed below.

You should keep some mention of using the configure script in this section, not completely remove it. You can make a reference to the new section.

Copy link
Collaborator Author

@mobin-2008 mobin-2008 Sep 19, 2025

Choose a reason for hiding this comment

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

Changed to this:

An alternative to "make mconfig" is to use the provided "configure" script. See "configure script",
below.

You can also create and edit the "mconfig" file completely by hand (or start by copying one for a
particular OS from the "configs" directory) to choose appropriate values for the configuration
variables defined within.

EDIT: Fixes misleading diff, mentions configure outside of its own section.

Copy link
Owner

@davmac314 davmac314 Sep 19, 2025

Choose a reason for hiding this comment

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

The process is to make the changes and push them to be reviewed (once questions raised in previous review are resolved), not to put the planned changes in comments. I would prefer not to clutter the review.



"configure" script
=-=-=-=-=-=-=-=-=-

An alternative to "make mconfig" is to use the provided "configure" script. It will try to
generate a suitable "mconfig" file, based on sensible defaults and options provided on the command
line when the script is run.
line when the script is run. It also has checks for the current system environment to
Copy link
Owner

Choose a reason for hiding this comment

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

Scratch "for the current system environment", that's not adding anything useful.

based on the availability of requirements (such as headers)

Based on the available of their requirements (i.e. the requirements for those features).

Change: headers -> presence of certain header files. (Some "headers" will always be available. The features need particular headers).

One important thing that "configure" does is to check whether certain compiler options are available. That needs to be mentioned, especially as that's what you're going on to talk about next.

enable/disable certain features based on the availability of requirements (such as headers).

The "configure" also checks for usability of the "-fno-rtti" compiler flag. This is achieved by
testing the flag itself and running a test source code to see if it works correctly. However,
because of the nature of cross-compiling, it's not possible to compile and run the test source
Comment on lines +52 to +54
Copy link
Owner

Choose a reason for hiding this comment

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

The "configure" also checks for usability of the "-fno-rtti" compiler flag

This paragraph launches in to a special case of configure behaviour without giving any background. This -fno-rtti option is a special case compared to other compilation options that are tested for, because it requires a test program to be run in order to ensure that the option functions correctly. Explain that first!! You can refer to the other section for a complete explanation, but you need to give context to understand why you are discussing something before you start discussing it.

I hope that you wrote a plan for this section, just like I suggested that you do when writing documentation.

You really need to re-write this section. Please start by developing a plan (as discussed previously) for what you need to say, review it to make sure it is cohesive (introduces topics in appropriate order), and post that (the plan) as a comment here, before you start trying to write the actual text.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I had a plan but now it's more clear.

  1. An introduction to configure and how it helps user to build Dinit
  2. An introduction to compiler options checking
  3. An introduction to "-fno-rtti" compiler flag, Why it's different from other flags and how configure checks against it
  4. Why configure cannot check for -fno-rtti when cross-compiling
  5. Cross-compiling warning message
  6. A link to "Special note about run-time type information" for more info about "-fno-rtti"
  7. Pointing out configure options for build adjustments

Copy link
Owner

Choose a reason for hiding this comment

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

"how it helps user to build Dinit" - can you elaborate on what is meant by this?
"An introduction to compiler options checking" - and this?

The rest seems basically ok.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"how it helps user to build Dinit" - can you elaborate on what is meant by this?

I mean explaining why configure is a viable option compared to make mconfig suggested earlier in the doc, because it's dynamic and this can be helpful.

"An introduction to compiler options checking" - and this?

I added this step to create contrast between -fno-rtti and other compiler options. Currently as you suggested -fno-rtti paragraph doesn't make sense because it doesn't highlight its difference from other compiler options.

Copy link
Owner

Choose a reason for hiding this comment

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

I mean explaining why configure is a viable option compared to make mconfig suggested earlier in the doc, because it's dynamic and this can be helpful.

Ok, but I don't think "dynamic" is the right word here. Also, remember that "make mconfig" actually runs configure on Linux anyway.

I added this step to create contrast between -fno-rtti and other compiler options

Ok, but what exactly will you write about for this step?

Copy link
Owner

Choose a reason for hiding this comment

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

I will change it if you think it's better this way.

(The problem is that you are leaning on me to identify problems, so that you can then fix them. I would rather that you properly consider all the relevant concerns yourself, and address them.)

Copy link
Collaborator Author

@mobin-2008 mobin-2008 Sep 30, 2025

Choose a reason for hiding this comment

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

I will change it if you think it's better this way.

(The problem is that you are leaning on me to identify problems, so that you can then fix them. I would rather that you properly consider all the relevant concerns yourself, and address them.)

In this thread you said with exception for the first and second steps in the plan

The rest seems basically ok.

So I focused mostly on those two.

Away from that, my idea behind such ordering (which I thought would make sense) was that steps 1-5 are the details about configure and last step (6) is a reference to configure itself outside of this doc for more information.

If you want to ask "Why didn't you consider mentioned thing in the section itself?" that's because I expect users to run configure without options i.e. more advanced users are going to tweak their build through options which is mentioned the step 6.

I tried and try to get my PRs and changes to a "perfect" state without much of review from you but I may get some things wrong and that's why I explain it to avoid misunderstanding about "Mobin is recklessly pushing changes/answering to comments"

And which points in the current plan are relevant, to people who are not cross-compiling?

1, 2, 5 and 6

Copy link
Owner

Choose a reason for hiding this comment

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

In this thread you said with exception for the first and second steps in the plan

The rest seems basically ok.

What I meant was that the points themselves seemed mostly ok, but that is still in the early stages of getting this in to shape. Once you fixed the first issues I pointed out, then I started to look at the structure, and that's where I'm finding concerns now.

1, 2, 5 and 6

2 and 5 don't add anything that isn't already covered elsewhere (and most people aren't going to be affected by the -fno-rtti issue anyway). So really, it's 1 and 6.

Which means that after a brief introduction (1) the average reader has to go through a bunch of detail about an issue that doesn't concern them (2-5) before they finally get to some perhaps useful information (6).

Do you agree, and if so do you see the problem? Or do you disagree?

If you want to ask "Why didn't you consider mentioned thing in the section itself?" that's because I expect users to run configure without options i.e. more advanced users are going to tweak their build through options which is mentioned the step 6.

Sorry, I don't quite understand what you are saying here, but I suspect you're not understanding why I am asking you these questions. I am asking you questions because I want you to think about them.

Your plan now at least makes sense - but I don't think it's a good structure, and I don't think you've thought about that.

I tried and try to get my PRs and changes to a "perfect" state without much of review from you but I may get some things wrong and that's why I explain it

I don't expect it to be perfect and it's good that you explain your thoughts.

But you need to understand and take on what I am telling you: you need to think about various aspects of documentation before and when you are writing it. I am trying to help you get better at this. If you can't think things through yourself, you'll always be relying on a reviewer to find the problems.

Copy link
Owner

Choose a reason for hiding this comment

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

Maybe, you mean something like "This is configure... It has checks...

"Maybe" isn't an answer. You need to address the question, not jump to suggesting changes. I don't mean "something like" anything. I am asking whether:

You don't think they would expect more general information - such as available configure options - to come before discussion of a specific problem that occurs in a very particular (and relatively uncommon) use case?

If you don't, then please explain why not. If you do, then: you need a solution, but I don't want to be asked whether a vague suggestion is ok or not. Figure out a change that will fix the issue, self-review to make sure it doesn't introduce new problems, and then propose it properly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In this thread you said with exception for the first and second steps in the plan

The rest seems basically ok.

What I meant was that the points themselves seemed mostly ok, but that is still in the early stages of getting this in to shape. Once you fixed the first issues I pointed out, then I started to look at the structure, and that's where I'm finding concerns now.

I understand.

1, 2, 5 and 6

2 and 5 don't add anything that isn't already covered elsewhere (and most people aren't going to be affected by the -fno-rtti issue anyway). So really, it's 1 and 6.

Which means that after a brief introduction (1) the average reader has to go through a bunch of detail about an issue that doesn't concern them (2-5) before they finally get to some perhaps useful information (6).

Do you agree, and if so do you see the problem? Or do you disagree?

I agree. I think the point of configure documentation is to provide

  1. An introduction to configure
  2. Explaining the -fno-rtti case

The issue here is that now they're mixed and this doesn't make much sense to the average reader.

If you want to ask "Why didn't you consider mentioned thing in the section itself?" that's because I expect users to run configure without options i.e. more advanced users are going to tweak their build through options which is mentioned the step 6.

Sorry, I don't quite understand what you are saying here, but I suspect you're not understanding why I am asking you these questions. I am asking you questions because I want you to think about them.

Your plan now at least makes sense - but I don't think it's a good structure, and I don't think you've thought about that.

I didn't understand what concerned you in the first place and what I said is pretty much irrelevant to this topic simply because the build tweak options is more important for the average reader than -fno-rtti issue and its check.

Aside from the issue, now I think I better understand what you meant by those question. I need to

  1. See what a good documentation looks like
  2. Apply the facts that makes documentation good to my own documentation

I tried and try to get my PRs and changes to a "perfect" state without much of review from you but I may get some things wrong and that's why I explain it

I don't expect it to be perfect and it's good that you explain your thoughts.

But you need to understand and take on what I am telling you: you need to think about various aspects of documentation before and when you are writing it. I am trying to help you get better at this. If you can't think things through yourself, you'll always be relying on a reviewer to find the problems.

Agree. I'm going to change the order of steps and also self-review it to make sure it's correct and well organized. I will try my best for propose a good plan for configure's doc.

code on the building machine, and instead, "configure" disables "-fno-rtti" in this case and prints
out this warning:

Cross-compilation detected. Disabling -fno-rtti to make sure exceptions will always work.

See "Special note for run-time type information", below, for more information about the "-fno-rtti"
flag.

For more information on available options from the configure script, run:

./configure --help

You can also create and edit the "mconfig" file completely by hand (or start by copying one for a
particular OS from the "configs" directory) to choose appropriate values for the configuration
variables defined within.


Main build variables
=-=-=-=-=-=-=-=-=-=-
Expand Down Expand Up @@ -140,9 +156,8 @@ Dinit should generally build fine with no additional options, other than:

Recommended options, supported by at least GCC and Clang, are:
-Os : optimise for size
-fno-rtti : disable RTTI (run-time type information), it is not required by Dinit. However, on
some platforms such as Mac OS (and historically FreeBSD, IIRC), this prevents
exceptions working correctly.
-fno-rtti : see "Special note for run-time type information", below. May cause Dinit to crash on
errors when compiled with Clang+libcxxrt on some platforms like FreeBSD.
Comment on lines +159 to +160
Copy link
Owner

@davmac314 davmac314 Sep 21, 2025

Choose a reason for hiding this comment

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

I missed this in review. It's not clear. You've removed the only explanation here of why this option is recommended, and are essentially forcing the user to read the "Special note" section - even if they're not using Clang - just to find out what the option is for.

"May cause Dinit to crash" is also vague and not helpful. (To clarify: terminating because of uncaught exception is certainly a possible result, but in general, there is no guarantee that Dinit will function correctly even in the absence of "errors" if exceptions don't work properly; even if that's the case currently, it's not something I'd want to guarantee or imply. Also "cause Dinit to crash" is just the wrong way to put this, the problem is with the compiler/runtime, not with Dinit, but this makes it sound like Dinit has an issue).

"when compiled with Clang+libcxxrt on some platforms like FreeBSD" is confusing. It doesn't explain what "Clang+libcxxrt" actually means, it doesn't explain that clang with libcxxrt is the default on FreeBSD (and on MacOS), it's not clear why FreeBSD is singled out.

The text was pretty much better before this change - except that:

  • we now know that the problem is caused by the combination of clang, libcxxrt, and perhaps the system dynamic linker
  • it still manifests on FreeBSD (not just "historically")
  • it's good that you added a reference to the new section explaining the issue in detail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I missed this in review. It's not clear. You've removed the only explanation here of why this option is recommended, and are essentially forcing the user to read the "Special note" section - even if they're not using Clang - just to find out what the option is for.

I got the idea from -D_GLIBCXX_USE_CXX11_ABI flag which doesn't explain the issue in itself rather explaining it in its own section but there is a problem, -D_GLIBCXX_USE_CXX11_ABI is a required flag that needs to be used on certain systems but -fno-rtti is a optional flag so it needs to explain what it does in itself. This is not good and I will fix it.

"May cause Dinit to crash" is also vague and not helpful. (To clarify: terminating because of uncaught exception is certainly a possible result, but in general, there is no guarantee that Dinit will function correctly even in the absence of "errors" if exceptions don't work properly; even if that's the case currently, it's not something I'd want to guarantee or imply. Also "cause Dinit to crash" is just the wrong way to put this, the problem is with the compiler/runtime, not with Dinit, but this makes it sound like Dinit has an issue).

It's a little tricky. I tried to minimize details as possible in user documentation to avoid confusion but this resulted in over-simplifying things. So to fix this -fno-rtti option should mention that 'it may stop Dinit from working correctly on platforms like FreeBSD and macOS. See "Special note for Clang/Libcxxrt", below for more details.' I think it's not vague anymore like it's now.

"when compiled with Clang+libcxxrt on some platforms like FreeBSD" is confusing. It doesn't explain what "Clang+libcxxrt" actually means, it doesn't explain that clang with libcxxrt is the default on FreeBSD (and on MacOS), it's not clear why FreeBSD is singled out.

This is a detail that I think should be explained in the special note. I've changed the text to only mention FreeBSD and macOS which are affected by this issue.
FreeBSD and macOS are going to mentioned with each other.
Is it necessary to mention that Clang+libcxxrt is the default compiler+runtime library on FreeBSD and macOS in this section rather in special note? I think not.

The text was pretty much better before this change - except that:
...

I think with the above fixes it will be better than previous explanation.

Copy link
Owner

Choose a reason for hiding this comment

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

Is it necessary to mention that Clang+libcxxrt is the default compiler+runtime library on FreeBSD and macOS in this section rather in special note? I think not.

The user needs to be aware whether they need to read that "special note" or note. You need to at least say that Clang together with the libcxxrt runtime is the default on "certain platforms" or something like that, but is it really so hard just to point the platforms we know about?

Do not expect that users have necessarily even heard of "libcxxrt" even if they are running MacOS or FreeBSD or another platform which uses it by default. Also, as I pointed out already, "clang+libcxxrt" is not a suitable way to refer to the combination of clang and libcxxrt in documentation.

Copy link
Owner

Choose a reason for hiding this comment

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

(Finally, just FYI, I plan on removing all mention of -D_GLIBCXX_USE_CXX11_ABI - it doesn't apply to newer versions of GCC, and I think you can no longer build with the versions where it does apply).

Copy link
Collaborator Author

@mobin-2008 mobin-2008 Sep 23, 2025

Choose a reason for hiding this comment

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

Is it necessary to mention that Clang+libcxxrt is the default compiler+runtime library on FreeBSD and macOS in this section rather in special note? I think not.

The user needs to be aware whether they need to read that "special note" or note. You need to at least say that Clang together with the libcxxrt runtime is the default on "certain platforms" or something like that, but is it really so hard just to point the platforms we know about?

So it should mention 'Clang with libcxxrt runtime library which is the default compiler with runtime library on platforms like FreeBSD and macOS'.

Do not expect that users have necessarily even heard of "libcxxrt" even if they are running MacOS or FreeBSD or another platform which uses it by default. Also, as I pointed out already, "clang+libcxxrt" is not a suitable way to refer to the combination of clang and libcxxrt in documentation.

I think mentioning 'Clang with libcxxrt runtime library' is enough for this purpose. Also I think 'Clang with libcxxrt runtime library' is better than "clang+libcxxrt".

-fno-plt : enables better code generation for non-static builds, but may cause unit test
failures on some older versions of FreeBSD (eg 11.2-RELEASE-p4 with clang++ 6.0.0).
-flto : perform link-time optimisation (option required at compile and link).
Expand Down Expand Up @@ -292,3 +307,26 @@ upgrading GCC. If you have libstdc++ corresponding to GCC 5.x or 6.x, you *must*
old ABI, but Dinit will be broken if you upgrade to GCC 7. If you have libstdc++ from GCC 7, you
*must* build with the new ABI. If the wrong ABI is used, Dinit may still run successfully but any
attempt to load a non-existing service, for example, will cause Dinit to crash.


Special note for run-time type information
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

RTTI, or run-time type information, is a feature of C++ that exposes information about an object's
data type at runtime. This can be used for "dynamic_cast<>" and to manipulate type information at
Copy link
Owner

Choose a reason for hiding this comment

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

exposes information about an object's data type at runtime

It exposes (at runtime) information about the dynamic type of objects. ("an object" means one object).

This can be used for "dynamic_cast<>"

Just say dynamic casts. It's not valid syntax as you've written it and anyway the syntax is not important here.

You say it "can be used for" dynamic casts, but it's actually necessary for some dynamic casts. So say that. I mentioned this in the previous review.

 and to manipulate type information at runtime using the "typeid" operator

How? What manipulation are you talking about? Give me an example please. (Not by pushing changes to the text).

'"typeid" operator' isn't important here. Don't discuss C++ syntax details, this is end-user documentation. Talk about the functionality (and only briefly).

GCC and Clang provide a compiler flag

"provide a compiler flag" -> "both support a flag"

which would disable RTTI generation

This isn't right.

It does (not "would") disable RTTI generation for some types.

So you can say, for example: "... which disables RTTI generation for some types".

However GCC would still generate RTTI for exception handling and therefore "-fno-rtti" is a viable option for saving output binary size

That doesn't make sense. You've said that GCC will still generate RTTI even if "-fno-rtti" is used, so it's not clear how it would reduce the size of the output binary. It needs to be made clear that less RTTI is generated (i..e RTTI for fewer types) when "-fno-rtti" is used. (That will perhaps mostly be taken care of, if you fix some of the other things I'm highlighting).

"generate RTTI for exception handling": This needs explanation/rewording. RTTI is for types, it is not "for exception handling".

You should talk about why it might be useful to avoid (or reduce) generation RTTI before you go into specifics of compiler behaviour, not afterwards.

Clang also still generates some RTTI necessary for exceptions. By only saying GCC, you seem to imply that Clang doesn't do that at all. (Do you understand the actual bug?)

Clang on some platforms (such as FreeBSD)

The platform itself is not the problem. Say what is it about those "some platforms" that makes the issue manifest.

And, if there's literally only two platforms we know of with this problem - give both. I don't understand why you would choose to highlight only one here.

Copy link
Owner

Choose a reason for hiding this comment

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

Edit:

It exposes (at runtime) information about the dynamic type of objects

It should be dynamic types of objects

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How? What manipulation are you talking about? Give me an example please. (Not by pushing changes to the text).

Hmm, after more research, I think I was misunderstood type manipulation, and I think I should remove it and only refer to some dynamic casts.

"generate RTTI for exception handling": This needs explanation/rewording. RTTI is for types, it is not "for exception handling".

I think the proper way to explain is to explain that exception types (classes) need RTTI to work.

Clang also still generates some RTTI necessary for exceptions. By only saying GCC, you seem to imply that Clang doesn't do that at all. (Do you understand the actual bug?)

I think I do. Clang does generate RTTI needed for exception types even after specifying -fno-rtti, but it's inconsistent and may break (I tested this myself before, and only the stoull() had this problem).

Copy link
Owner

Choose a reason for hiding this comment

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

Ok.

I think I do. Clang does generate RTTI needed for exception types even after specifying -fno-rtti, but it's inconsistent

(inconsistent with what)?

It sounds like you don't really understand. The issue occurs when the exception is thrown from a function compiled with -frtti (the default) and then the catch clause is in a a function compiled with -fno-rtti. The catch and throw both need RTTI but the RTTI generated will be different (a "minimal" RTTI is generated for the "no RTTI" case) and won't be deduplicated, so the catch and throw now use different RTTI and the catch doesn't recognise the thrown type and so won't catch the exception. For applications (such as Dinit) this presents a problem when they are compiled with -fno-rtti and try to catch exceptions thrown by the standard library (compiled with -frtti). This is all explained in the issue.

I tested this myself before, and only the stoull() had this problem

Likely that's the only case you tested where the exception was thrown by (non-inline code in) the standard library.

None of these details really matter, but it's not the case that Clang doesn't generate RTTI for types used as exceptions. So, again, you shouldn't imply that it is the case. I don't expect a full explanation of the bug, but whatever you do say should to be accurate.

Copy link
Owner

Choose a reason for hiding this comment

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

Hmm, after more research, I think I was misunderstood type manipulation

It worries me a lot that you wrote what you did without having some idea of what it meant. If you can't give an example of something when asked what it means you really need to do more research before you get asked about it in a review. Don't just write something if you only have a vague idea about what it means!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

(inconsistent with what)?
It sounds like you don't really understand. The issue occurs when the exception is thrown from a function compiled with -frtti (the default) and then the catch clause is in a a function compiled with -fno-rtti. The catch and throw both need RTTI but the RTTI generated will be different (a "minimal" RTTI is generated for the "no RTTI" case) and won't be deduplicated, so the catch and throw now use different RTTI and the catch doesn't recognise the thrown type and so won't catch the exception. For applications (such as Dinit) this presents a problem when they are compiled with -fno-rtti and try to catch exceptions thrown by the standard library (compiled with -frtti). This is all explained in the llvm/llvm-project#66117.

Likely that's the only case you tested where the exception was thrown by (non-inline code in) the standard library.

I mean its working is inconsistent, sometimes it does work and sometimes it doesn't. I knew that this was caused by mentioned issue but I had the idea that all exceptions to should not be caught because of that which you pointed it for me that why it didn't show in my testing.

None of these details really matter, but it's not the case that Clang doesn't generate RTTI for types used as exceptions. So, again, you shouldn't imply that it is the case. I don't expect a full explanation of the bug, but whatever you do say should to be accurate.

Agree, I will fix this.

runtime using the "typeid" operator. Exception handling also uses the same info.

GCC and Clang provide a compiler flag ("-fno-rtti") which would disable RTTI generation. However
GCC would still generate RTTI for exception handling and therefore "-fno-rtti" is a viable option
for saving output binary size.

Clang on some platforms (such as FreeBSD) would break handling of certain exceptions when using
"-fno-rtti" and this will result in Dinit crashing when an error occurs (such as when loading a
non-existing service).

Details regarding the issue with Clang can be found here:

https://github.com/llvm/llvm-project/issues/66117

To avoid Dinit crashes when using Clang+libcxxrt it's recommended to not use the "-fno-rtti" flag.
Copy link
Owner

Choose a reason for hiding this comment

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

This is the very first time libcxxrt has been mentioned. This is extremely confusing. If libcxxrt is part of the issue, it should be mentioned earlier. Instead of saying something like "Clang on some platforms (such as FreeBSD)" you could be saying "Clang on platforms which also use libcxxrt as the C++ runtime library".

Clang+libcxxrt is the default compiler+runtime-library on platforms like FreeBSD and macOS.
134 changes: 111 additions & 23 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,34 @@ cxx_works()
fi
}

# Test if the compiler successfully compiles the specified source file. If the optional compilation
# argument is specified ($3) then pass it to the compiler along with the already-established
# arguments (this can be used to test if the compiler accepts the argument).
# $1 - the name of the source file to compile
# $2 - the name of the result object file
# $3 - the argument to test (optional)
# CXX - the name of the compiler
# CXXFLAGS, CXXFLAGS_EXTRA - any predetermined flags
try_compile_source()
{
eval $CXX $CXXFLAGS ${3:-} $CXXFLAGS_EXTRA '"$configtmpdir"/"$1"' \
-c -o '"$configtmpdir"/"$2"' > /dev/null 2>&1
}

# Test if the specified object file can be linked into an executable. If the optional link argument
# is specified ($3) then pass it to the compiler driver along with the already-established
# arguments (this can be used to test if the linker accepts the argument).
# $1 - the name of the object file to link
# $2 - the name of the result executable file
# $3 - the argument to test (optional)
# CXX - the name of the compiler
# LDFLAGS, LDFLAGS_EXTRA - any predetermined flags
try_link_object()
{
eval $CXX $LDFLAGS $LDFLAGS_EXTRA ${3:-} '"$configtmpdir"/"$1"' \
-o '"$configtmpdir"/"$2"' > /dev/null 2>&1
}

# Test if the compiler accepts an argument (for compilation only); if so add it to named variable.
# Note: this function will return failure if the flag is unsupported (use try_optional_cxx_argument
# instead, to avoid errorring out).
Expand All @@ -93,8 +121,7 @@ cxx_works()
try_cxx_argument()
{
info Checking whether "$2" is accepted for compilation...
if eval $CXX $CXXFLAGS $2 $CXXFLAGS_EXTRA $LDFLAGS $LDFLAGS_EXTRA '"$configtmpdir"/testfile.cc' \
-c -o '"$configtmpdir"/testfile.o' > /dev/null 2>&1; then
if try_compile_source testfile.cc testfile.o "$2"; then
rm "$configtmpdir"/testfile.o
sub_info Yes.
eval "$1=\"\${$1} \$2\""
Expand Down Expand Up @@ -127,14 +154,12 @@ try_ld_argument()
info Checking whether "$2" is accepted as a link-time option...
if [ ! -e "$configtmpdir"/testfile.o ]; then
# If the object file doesn't exist yet, need to compile
if ! eval $CXX $CXXFLAGS $CXXFLAGS_EXTRA '"$configtmpdir"/testfile.cc' \
-c -o '"$configtmpdir"/testfile.o' > /dev/null 2>&1; then
if ! try_compile_source testfile.cc testfile.o; then
sub_info "No (compilation failed)."
return
fi
fi
if eval $CXX $LDFLAGS $LDFLAGS_EXTRA $2 '"$configtmpdir"/testfile.o' \
-o '"$configtmpdir"/testfile' > /dev/null 2>&1; then
if try_link_object testfile.o testfile "$2"; then
sub_info Yes.
rm "$configtmpdir"/testfile
eval "$1=\"\${$1} \$2\""
Expand All @@ -145,27 +170,71 @@ try_ld_argument()
}

# Test if an argument is supported during both compiling and linking.
# $1 - the name of the compiler-flags variable to potentially add the argument to
# $2 - the name of the link-flags variable to potentially add the argument to
# $1 - the name of the compiler-flags variable to potentially add the argument to (or specify the
# dash ("-") to skip adding to the variable)
# $2 - the name of the link-flags variable to potentially add the argument to (or specify the
# dash ("-") to skip adding to the variable)
# $3 - the argument to test/add
# CXX - the name of the compiler
# CXXFLAGS, CXXFLAGS_EXTRA, LDFLAGS, LDFLAGS_EXTRA - any predetermined flags
try_both_argument()
{
info Checking whether "$3" is accepted for compiling and linking...
if eval $CXX $CXXFLAGS $CXXFLAGS_EXTRA $LDFLAGS $LDFLAGS_EXTRA $3 "$configtmpdir"/testfile.cc \
-o "$configtmpdir"/testfile > /dev/null 2>&1; then
if try_compile_source testfile.cc testfile.o "$3" && try_link_object testfile.o testfile "$3"; then
sub_info Yes.
rm "$configtmpdir"/testfile.o
rm "$configtmpdir"/testfile
eval "$1=\"\${$1} \$3\""
eval "$1=\${$1# }"
eval "$2=\"\${$2} \$3\""
eval "$2=\${$2# }"
if [ "$1" != "-" ]; then
eval "$1=\"\${$1} \$3\""
eval "$1=\${$1# }"
fi
if [ "$2" != "-" ]; then
eval "$2=\"\${$2} \$3\""
eval "$2=\${$2# }"
fi
else
sub_info No.
fi
}

# Test if the specified header is usable.
Copy link
Owner

Choose a reason for hiding this comment

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

Here you say "specified" header (good!). Why "passed" before? Please be consistent.

# $1 - the name of the variable to set to 1 or 0 based on header availability
# $2 - the header path
check_header()
{
info Checking whether "$2" header is available...
echo "#include <$2>" > "$configtmpdir/testheader.cc"
if try_compile_source testheader.cc testheader.o; then
sub_info "Yes."
rm "$configtmpdir"/testheader.o
eval "$1=1"
else
sub_info "No."
eval "$1=0"
fi
}

# Write the test code for testing exception handling with -fno-rtti
write_no_rtti_check()
{
cat << _EOF > "$configtmpdir"/no-rtti-check.cc
#include <string>
#include <stdexcept>

int main()
{
try {
std::stoull("invalid for stoull");
}
catch (std::invalid_argument &exc) {
return 0;
}

return -1;
}
_EOF
}



# Quote a string to preserve its original form after shell evaluation (except that an empty
Expand Down Expand Up @@ -399,7 +468,7 @@ if [ "$PLATFORM" = "Linux" ]; then
: "${BUILD_SHUTDOWN:="yes"}"
: "${SUPPORT_CGROUPS:="1"}"
: "${SUPPORT_CAPABILITIES:="AUTO"}"
: "${SUPPORT_IOPRIO:="0"}" # the required header <linux/ioprio.h> may not be available
: "${SUPPORT_IOPRIO:="AUTO"}"
: "${SUPPORT_OOM_ADJ:="1"}"
: "${SYSCONTROLSOCKET:="/run/dinitctl"}"
else
Expand Down Expand Up @@ -501,20 +570,37 @@ if [ "$AUTO_CXXFLAGS" = "true" ]; then
do
try_optional_cxx_argument CXXFLAGS $argument
done
if [ "$PLATFORM" != "Darwin" ]; then
try_optional_cxx_argument CXXFLAGS -fno-rtti

# -fno-rtti is a special case. Clang+libcxxrt is known for generating broken code
# when disabling run-time type information with code which uses exceptions.
info Checking whether -fno-rtti is accepted for compilation...
if [ -n "${CXX_FOR_BUILD:-}" ]; then
# May not be able to execute the check when cross-compiling.
sub_info Cross-compilation detected. Disabling -fno-rtti to make sure exceptions will always work.
else
write_no_rtti_check
if try_compile_source no-rtti-check.cc no-rtti-check.o -fno-rtti; then
sub_info "Yes."
info Checking whether -fno-rtti breaks exceptions...
if try_link_object no-rtti-check.o no-rtti-check && "$configtmpdir"/no-rtti-check; then
sub_info "No."
CXXFLAGS="$CXXFLAGS -fno-rtti"
else
sub_info "Yes. Disabling -fno-rtti"
fi
else
sub_info "No."
fi
fi
fi
if [ "$AUTO_LDFLAGS" = true ] && [ "$AUTO_CXXFLAGS" = true ]; then
DUMMY_LDFLAGS=""
# -flto must work for both compiling and linking, but we don't want to add it to LDFLAGS as,
# if LTO is used, CXXFLAGS will always be used alongside LDFLAGS.
if try_both_argument CXXFLAGS DUMMY_LDFLAGS -flto; then
if try_both_argument CXXFLAGS - -flto; then
HAS_LTO="true"
else
HAS_LTO="false"
fi
unset DUMMY_LDFLAGS
fi
if [ "$AUTO_LDFLAGS_BASE" = true ] && [ "$PLATFORM" = FreeBSD ]; then
try_ld_argument LDFLAGS_BASE -lrt
Expand All @@ -537,6 +623,10 @@ else
LDFLAGS_LIBCAP=""
fi

if [ "$SUPPORT_IOPRIO" = "AUTO" ]; then
check_header SUPPORT_IOPRIO "linux/ioprio.h"
fi

# "XXX_MK" variables are for values already quoted for use in makefiles. The following will now be
# set: TEST_LDFLAGS_BASE_MK, LDFLAGS_MK, TEST_LDFLAGS_MK, TEST_CXXFLAGS_MK. For other build
# variables, we'll just do the quoting when we write the value to mconfig.
Expand Down Expand Up @@ -588,18 +678,16 @@ fi

# Check whether sanitizers can be used for tests
if [ "$AUTO_TEST_LDFLAGS" = "true" ] && [ "$AUTO_TEST_CXXFLAGS" = "true" ]; then
DUMMY_LDFLAGS=""
if [ "$HAS_LTO" = true ]; then
# Avoid doubling-up sanitizer options
LDFLAGS_VAR=DUMMY_LDFLAGS
LDFLAGS_VAR=-
else
LDFLAGS_VAR=TEST_LDFLAGS_MK
fi
# (Note that we append directly to TEST_CXXFLAGS_MK/TEST_LDFLAGS_MK here)
CXXFLAGS="$established_TEST_CXXFLAGS" CXXFLAGS_EXTRA="$TEST_CXXFLAGS_EXTRA" \
LDFLAGS="$established_TEST_LDFLAGS" LDFLAGS_EXTRA="$TEST_LDFLAGS_EXTRA" \
try_both_argument TEST_CXXFLAGS_MK $LDFLAGS_VAR -fsanitize=address,undefined
unset DUMMY_LDFLAGS
fi

## Create mconfig
Expand Down