Re: [webkit-dev] Stop Using Raw Pointers & References in New Code

2023-01-24 Thread Alicia Boya García via webkit-dev

On 12/01/2023 06.21, Ryosuke Niwa via webkit-dev wrote:
I suggest we *stop using raw pointers and references in any local or 
heap stored variable*.


I don't think this is feasible for code using non-WebKit libraries, and 
would expect it to not apply to such cases.


For instance, many GLib and GStreamer objects are refcounted, and we 
even have smart pointers for them in WebKit: GRefPtr, which refs/unref 
using RAII, and GUniquePtr, which frees GLib non-refcounted objects.


We use both GRefPtr/GUniquePtr and raw pointers, but the meaning of each 
is different:


GRefPtr and GUniquePtr mean the code owns a reference, and will 
unref/free when the variable goes out of scope. Raw pointer means the 
code is borrowing a reference. The code will do something with the 
object, then leave it, without establishing ownership of a reference to 
it. This is especially the case for const raw pointers, which you are 
meant to use within scope and are not allowed to free() them, as you are 
just borrowing them.
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] [MSE] Range ends inclusion is deleting wanted MediaSample's

2017-11-14 Thread Alicia Boya García
On 14/11/17 22:55, Jer Noble wrote:
> 
> Yeah, the spec is not the best here. 

I agree. While WebKit replicates the specified steps faithfully, it's
not clear they are good steps in the first place.

I spent quite a bit of time trying to wrap my head around the three (!)
frame removal cases, all of them apparently doing the same but with
slightly different ranges and being used in slightly different situations...

Even after all the complexity I found too some cases that are unhandled
by the spec.

> If you have, e.g. a sample with a
> PTS of 0 and a duration of 100, and then insert a sample with a PTS of
> 50 and a duration of 100, you’d expect that to cause the first sample to
> be removed. But a strict reading of the spec says that sample stays.

Or maybe cropped (that would be of questionable utility in practice
though)... But yup, the spec says that (supposing they are consecutive)
no check at all is performed because PTS < highestEndTimestamp.

>  Now you have two overlapping samples.  It can get even weirder if you
> insert a sample with a PTS of 25 and a duration of 50.  Now, strictly
> implementing the spec, you have a sample overlaps on both ends of
> another sample.  What does that even mean for a decoder?  It’s almost
> guaranteed to generate a decode error, unless both of the overlapping
> samples are I-frames.

It would be implementation specific. In the case of GStreamer, for
instance, durations are not needed for decoders to work, only DTS. Same
can be said for the presentation, that only needs to know the total
length of the movie (or at the very least know whether it should
continue playing) and the PTS of each frame. So the first frame would be
shown for 25 ms, then the second one for 75 ms. No corruption should
occur as the frames have been decoded in the correct order.

More serious problems can arise from manipulating the array of frames as
many assumptions would be broken: frames would be played for less than
their declared durations, the relation "time to frame" would no longer
have 0..1 multiplicity, the sum of durations would be longer than the
last frame end even though they are thought to be consecutive and the
first frame has PTS=0 and so on... Definitively undesirable consequences
independently of the platform.

> 
> I think the intent of the spec is clear: if any part of a previous
> sample overlaps the new one, it has to be removed, and all samples that
> depend on the removed samples must be removed as well.  And in order to
> do that, you have to take the entire duration of the sample into account.
> 

I wish that part of the MSE spec was rewritten in a simpler yet more
comprehensive way... because as of today, that's not what the spec says.
Some complexity may need to appear nevertheless because of the float
conversions caused by JS interaction.

-- Alicia.
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] [MSE] Range ends inclusion is deleting wanted MediaSample's

2017-11-14 Thread Alicia Boya García
Hi, Jer.

Sorry for the late reply, I've been busy investigating all of this.

I'm replying to your points in reverse order...

On 09/11/17 23:23, Jer Noble wrote:
>> As I understand it, the point of that part of the algorithm is to delete
>> old samples that are -- even partially -- in the presentation time range
>> of the newly appended one, but using (beginTime, endTime] fails to
>> accomplish that in two cases:
>>
>> a) If there is an existing MediaSample with PTS=9 and DUR=1 it will not
>> be removed because beginTime (=9) is exclusive.
>
> Eh, not really. The search space is the entire duration of the sample,
> so an exclusive beginTime of 9 _should_ match PTS=9, DUR=1 because 9 <
> presentationEndTime=10.  I’m pretty sure this is correct, but a mock
> test case should clear this up pretty quickly.

That's totally not the case, though the first time I gave a look at this
code I thought that too... presentationRange() is a std::map whose
key type is a single MediaTime specifying the PTS of the MediaSample,
not the duration or the full presentation time range.

Also, neither findSamplesWithinPresentationRange() or its siblings take
durations into account, as they search only with the key (PTS) in
mind... Well, actually findSamplesWithinPresentationRangeFromEnd() looks
at the values, but it only checks .presentationTimestamp() so it's
functionally the same.

Adding a sample with same PTS as an existing one does not remove the old
one with this check. There are two possible behaviors that can mask the
issue:

a) The previous frame removal step (see step 1.13 in the spec or 1.14 in
WebKit) removed the overlapping frame. This is only the case if the
frame started a new Coded Frame Group.

b) The existing overlapping frame was not removed, but later on when the
new MediaSample was passed to std::map::insert() it was ignored because
it was a duplicated key (same PTS as the existing overlapping frame).

You can confirm that it's the old MediaSample the one persisted by
setting different durations for the old and the new one but the same
PTS. After the append of the second frame, the old duration persists and
there are no new frames in the TrackBuffer.

On 09/11/17 23:23, Jer Noble wrote:
>> My question is... shouldn't the range ends inclusivity be the other way
>> around i.e. [beginTime, endTime)?
> 
> beginTime was intended to be exclusive so that, given a [0, 9] range, 
> searching for (9, 10] wouldn’t match the last sample in the [0, 9] range.
> 
> But now that you mention it, perhaps the real problem is that both beginTime 
> _and_ endTime should be exclusive.

This is not an issue because as explained before we are considering just
the frame start PTS, not its entire presentation interval.

beginTime must be inclusive so that old frames with the same PTS are
deleted. endTime must be exclusive so that non overlapping consecutive
frames are not deleted.

I have checked this with the spec:
https://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-processing

1.14. Remove existing coded frames in track buffer:
 -> If highest end timestamp for track buffer is not set:
   [...]
 -> If highest end timestamp for track buffer is set and less than or
equal to presentation timestamp:
   Remove all coded frames from track buffer that have a
   presentation timestamp greater than or equal to highest end
   timestamp and less than frame end timestamp.


On 09/11/17 23:23, Jer Noble wrote:
> It should be possible to make a “mock” testcase which doesn’t rely on
> any particular media engine and which can demonstrate this bug.

I just finished doing that. I have written two new MediaSource tests
using video/mock: one that demonstrates how existing frames whose PTS
coincide with the start of the range of the range are not deleted and
another one that demonstrates how existing frames whose PTS coincide
with the end of the range are deleted.

I have also written a patch with the correct checks:
https://bugs.webkit.org/show_bug.cgi?id=179690

-- Alicia.
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


[webkit-dev] [MSE] Range ends inclusion is deleting wanted MediaSample's

2017-11-09 Thread Alicia Boya García
Hi, WebKittens!

In the YouTube Media Source Extensions conformance tests there is one
called 36.AppendOpusAudioOutOfOrder where two audio media segments are
appended out of order to a SourceBuffer: First, a segment with the PTS
ranges [10, 20) is added. Then, another one with [0, 10) is added.

(I have rounded the actual timestamps to near integers for easier
understanding).

Almost at the very end of the process the buffered ranges are like this:

[ 0,  9)
[10, 20)

At this point, SourceBuffer::sourceBufferPrivateDidReceiveSample() is
called with the last audio frame, that has PTS=9 and DUR=1.

The execution reaches this conditional block:

```
if (trackBuffer.highestPresentationTimestamp.isValid() &&
trackBuffer.highestPresentationTimestamp <= presentationTimestamp) {
```

trackBuffer.highestPresentationTimestamp contains the highest PTS so far
within the current segment. The condition is true (9 <= 9) as expected
for sequentially appended frames.

Inside there is this block of code:

```
MediaTime highestBufferedTime = trackBuffer.buffered.maximumBufferedTime();

PresentationOrderSampleMap::iterator_range range;
if (highestBufferedTime - trackBuffer.highestPresentationTimestamp <
trackBuffer.lastFrameDuration)
range =
trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRangeFromEnd(trackBuffer.highestPresentationTimestamp,
 frameEndTimestamp);
else
range =
trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp,
frameEndTimestamp);

if (range.first != trackBuffer.samples.presentationOrder().end())
erasedSamples.addRange(range.first, range.second);
```

The first if block there is an optimization, it decides whether to do a
binary search in the entire collection of MediaSample's or do a linear
search starting with the MediaSample with the highest PTS (which is
faster when appends always occur at the end), but the result is the same
in both cases.

presentationOrder() is a std::map.

findSamplesWithinPresentationRange(beginTime, endTime) and its *FromEnd
counterpart both return a pair of STL-style iterators which cover a
range of MediaSample objects whose presentation timestamps sit in the
range (beginTime, endTime] (beginTime is exclusive, endTime is inclusive).

Then, it marks those MediaSample objects (frames) for deletion.

My question is... shouldn't the range ends inclusivity be the other way
around i.e. [beginTime, endTime)?

As I understand it, the point of that part of the algorithm is to delete
old samples that are -- even partially -- in the presentation time range
of the newly appended one, but using (beginTime, endTime] fails to
accomplish that in two cases:

a) If there is an existing MediaSample with PTS=9 and DUR=1 it will not
be removed because beginTime (=9) is exclusive.

b) If there is an existing MediaSample with PTS=10 and DUR=1 it WILL be
removed even though there is no overlap with the sample being appended
(PTS=9 DUR=1) because endTime (=10) is inclusive. This is exactly what
is making the YTTV test fail in my case.

Before:

[ 0,  9)
[10, 20)

Expected result after adding [9, 10):

[0, 20)

Actual result in WebKit:

[ 0, 10)
[11, 20)


-- Alicia.
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] Growing tired of long build times? Check out this awesome new way to speed up your build... soon (HINT: It's not buying a new computer)

2017-08-29 Thread Alicia Boya García
On 08/30/2017 12:00 AM, Keith Miller wrote:

> The automated system should handle your concern about bundling similar .cpp 
> files together. The proposed system bundles by directory and also sorts the 
> files in those directories when dividing up the files. Is there any reason to 
> think that we would not do roughly the same thing if we were bundling by hand?

As long as the sets are generated consistently that approach should be
equally fine and indeed it would reduce the burden for contributors. You
may need at least a file to write exceptions (files not to be included
in any bundle) though.

-- Alicia.

___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] Growing tired of long build times? Check out this awesome new way to speed up your build... soon (HINT: It's not buying a new computer)

2017-08-29 Thread Alicia Boya García
I'm all for stable bundle .cpp files. Automatic generation can be nice
for the first time... and once in while we can try to modify the bundles
to try to make the build even faster, but really most of the time bundle
contents should not change unless new files are added and everybody
should get the same bundles.

If we're going to end up with some name collisions, we'd rather do so
that every build of the same source tree gets collisions or no build
gets them.

The description of these .cpp bundles should become a project artifact,
shared and versioned in the repository and treated carefully as such.

Also, in my earlier message about unified builds I explained how the
distribution of the files within the bundles also affects the number of
bundles that are rebuilt in response to changes in the source code. I
also proposed that grouping together files implementing the same
features could be a good start point to minimize the impact of this issue.

On other note, I don't think namespacing static functions and variables
as originally proposed is the way to go.

The refactor would be ridiculously huge. Running `rg -w '^static' -tcpp
--no-filename --no-heading |wc -l` in my local repository yields 16797
instances of static functions and variables, only taking into account
those where the word static is at the beginning of the line without any
spaces before, which is a common case but not a requirement in C++. Note
though that this regex excludes static class members as long as code is
properly formatted (they would be indented); these are not included as
they would not need any changes.

static functions and variables in WebKit are used for hidden
implementation details, which tend to very very specific and therefore
receive long specific names with relatively little risk of collisions.

Furthermore, collisions won't go unnoticed as in every case they will
trigger a compilation error of the likes of 'redefinition of ‘int a’'.
In this case the compiler will also show the inclusion stack mentioning
the bundle file and the conflicting definition. The programmer will
notice that both are static members in .cpp files, so the only way that
error can arise is because they had a name collision due to unified
source builds.

We'd probably be better off handling the few collisions on a one by one
basis, renaming the symbols or excluding the worst offenders from
unified builds rather than plain out forbidding static declarations.

-- Alicia
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] Growing tired of long build times? Check out this awesome new way to speed up your build... soon (HINT: It's not buying a new computer)

2017-08-29 Thread Alicia Boya García
On 08/29/2017 06:20 AM, Daniel Bates wrote:

> Do we know what is the cause(es) for the slow clean builds? I am assuming 
> that much of the speed up from the "unified source" comes from clang being 
> able to use an in-memory #include cache to avoid disk I/O and re-parsing of a 
> seen header. Have we exhausted all efforts (or have we given up?) removing 
> extraneous #includes? Do we think this pursuing this effort would be more 
> time consuming or have results that pale in comparison to the "unified 
> source" approach?

Whilst having an in-process-memory #include cache is not a bad thing,
it's not the greatest gain as the operating systems should already cache
file reads just fine.

The greatest gain comes from reducing the amount of times C++ headers
are parsed. If you are building a certain .cpp file and include a .h
file, the compiler has to parse it, which can take quite a bit because
C++ is really complex monster, especially when templates are used. Doing
this more than necessary raises build times really quickly.

Header files almost always are include-guarded (either with #pragma once
or traditional #ifndef guards), so including the same header twice
within the same .cpp file (or any of its included files) has no cost. On
the other hand, if you then start building a different .cpp file that
also includes the same header, you have to parse it again because so far
C++ is concerned, every inclusion could add different symbols to the AST
the compiler is building, so their output can't be reused*. In turn we
end up parsing most headers many more times than actually needed (i.e.
for every .cpp file that includes Node.h the compiler has to parse
Node.h and all its dependencies from source, that's a lot of wasted
effort!).

*Note that including twice the same .h within the same .cpp file is not
fast because the output is cached in anyway, but because the entire .h
file is skipped, adding no additional nodes to the AST.

The goal of C++ modules is to fix this problem from its root cause:
instead of literally including text header files, .cpp files declare
dependencies on module files that can be compiled, stored, loaded and
referenced from .cpp files in any order, so you would only parse the
Node module source code once for the entire project, whilst the compiler
could load directly the AST every other time from a cached module object
file.

Note the great advantage of modules comes from the fact that they can be
imported in different contexts and their content is still semantically
equivalent, whereas with plain C/C++ includes every header file may act
differently depending on the preprocessor variables defined by the
includer and other previous inclusions. In the worst case, when they are
not include-guarded (luckily this is not too common, but it still
happens), even including the same file in the same .cpp twice could add
different symbols each time!

Unfortunately C++ modules are a work in progress... There are two
different competing proposals with implementations, one from Clang and
another one from Microsoft, and the C++ technical specification is in a
very early stage too:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4681.pdf

We know for sure modules are very important for the future of C++, but
maybe it's still a bit too early to bet a big project like WebKit on them.

So how else can we avoid parsing the same header files so many times and
speed up our builds? Enter unified builds.

A requirement for unified builds to work correctly is that header files
are coded in such a way they work as independent units, much like C++
modules, i.e. including headers should work no matter in what order you
place them, and in each case they must define the same symbols. On July
31 I wrote about some issues we currently have because of not doing
exactly this in WebKit (particularly, our #include "config.h" lines are
ambiguous). They can be worked around so they will not become blockers
for unified builds, but I still think we should fix them at some point.

Once you have a set of .cpp files whose includes all (1) are guarded
(e.g. by #pragma once) and (2) are independent units according to the
above rule, you can take advantage of unified builds:

Instead of invoking once the compiler for each .cpp file, you create a
new artificial "unified" or "bundle" .cpp file that concatenates (or
#include's) a number of different .cpp files. This way, headers included
within the bundle are parsed only once, even if they are used by
different individual .cpp files, as long as they are within the same
bundle. This can often result in a massive build speed gain.

Unfortunately, there are some pitfalls, as there is a dissonance between
what the programmer thinks the compilation unit is (the individual .cpp
file) and the actual compilation unit used by the compiler (the bundle
.cpp file).

* `static` variables and functions are intended to be scoped to the
individual .cpp file, but the compiler has no way to kno

Re: [webkit-dev] Python

2017-08-14 Thread Alicia Boya García
On 08/12/2017 11:40 PM, Ryosuke Niwa wrote:
> On Fri, Aug 11, 2017 at 8:06 AM, Michael Catanzaro
>  wrote:
>> On Mon, Aug 7, 2017 at 10:56 AM, Carlos Alberto Lopez Perez
>>  wrote:
>>>
>>> That's a good thing.
>>>
>>> I believe all Linux distros we support have this, right?
>>> And all the scripts actually assume python2.7 (AFAIK).
>>>
>>> Would it work for everyone having as shebang :
>>>
>>> #!/usr/bin/env python2.7
>>>
>>> ?
>>
>>
>> So this is by far the easiest solution of those that have been proposed. I
>> think we should try this as a stopgap until macOS is fixed to provide a
>> python2 binary.
> 
> What's wrong with using that as the permanent solution until we make
> it Python3 compatible?
> 
> I don't think it's wise to assume /usr/bin/python2 will be added on
> Mac anytime soon.
> 
> - R. Niwa
> ___
> webkit-dev mailing list
> webkit-dev@lists.webkit.org
> https://lists.webkit.org/mailman/listinfo/webkit-dev
> 

+1, python2.7 is well supported among different systems.

It would be desirable to move to Python 3 eventually, but that's an
endeavor that should not be taken lightly, as many things can break in
subtle ways.

--
Alicia
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


Re: [webkit-dev] What's the rationale for not including config.h in any header files?

2017-08-01 Thread Alicia Boya García
On 08/01/2017 08:25 AM, Darin Adler wrote:
>> On Jul 31, 2017, at 2:04 PM, Michael Catanzaro  wrote:
>>
>> On Mon, Jul 31, 2017 at 9:27 PM, Darin Adler  wrote:
>>> I don’t think we should add lots of includes of “config.h”, though. I think 
>>> we can come up with something better.
>>
>> Like what?
> 
> We should consider reducing the size of “config.h” and only use it for things 
> that it’s really needed for, using more conventional header includes for 
> other purposes.
> 
> Ideally we would eliminate “config.h” entirely and replace it with normal 
> headers.
> 
> I definitely don’t think we need to use the same name, “config.h”, for 9 
> separate headers that don’t have the same contents in 9 different directories 
> in the overall WebKit source code. A risk of putting includes of “config.h” 
> in header files is that it isn’t clear which of the “config.h” files will be 
> included. If we aren’t obliged to use the name “config.h” because of 
> autotools, then perhaps we can name these more in line with WebKit coding 
> style, something like WebCoreConfiguration.h, but also strive to get rid of 
> them entirely.
> 
> In projects not using autotools and using IDEs to build I often see a header 
> referred to as the “prefix” that is automatically included by the IDE, with 
> no #include statements at all in the source files. That’s used as a sort of 
> substitute for #define statements on the command line and is what I used 
> before I became familiar with autotools.
> 
> I am concerned to see there is also a header named “cmakeconfig.h” so maybe 
> we do need “config.h”.
> 
> — Darin
> ___
> webkit-dev mailing list
> webkit-dev@lists.webkit.org
> https://lists.webkit.org/mailman/listinfo/webkit-dev
> 

I'm not sure if it's realistic to get rid of configuration headers.
WebKit development builds use just too many build-time flags to enable
features.

On the other hand, I agree completely in the name issue, which is also
an scoping issue. The situation I found is something like this:

"cmakeconfig.h" is a file generated by CMake with all the flags we
enable at configure time. One reason to do that is precisely because
there are too many to put comfortably in the command line (I count 177
#define's there).

There is a single cmakeconfig.h file for an entire WebKit build. This
makes sense: If a feature is implemented in both WebCore and WebKit you
want it to be enabled either both or in none.

On the other hand, there is currently a config.h file in every of our
sub-project directories: WTF, WebCore, JavaScriptCore, WebKit and
WebDriver. Every config.h file includes cmakeconfig.h, plus some other
stuff. Unfortunately, the kind of "stuff" that is additionally included
or defined varies a lot between sub-projects.

Having several files called config.h is confusing at the very least,
even more when they are included from different sub-projects. The same
#include "config.h" line refers to different files in different contexts.

This is a quite nasty problem, as the author of a header file in a
sub-project may assume it's safe to rely on something being defined
because it's included in that sub-project's config.h file... and most of
the time it will work, but it may not be the case when that file is
included (even transitively) by any other file from other sub-project
that uses a different config.h file.

As a consequence, quirks often have to be added to config.h files of
projects with dependencies. For instance, JavaScriptCore/config.h
includes "runtime/JSExportMacros.h" (and therefore many headers in JSC
assume it is included) and the same happens in WebCore, whose config.h
includes "WebCore/PlatformExportMacros.h". The WebKit sub-project
includes headers from both, so its config.h has to include both
"runtime/JSExportMacros.h" and "WebCore/PlatformExport.h" too in order
to build.

Complicating things a bit more there is
ThirdParty/gtest/include/gtest/internal/gtest-port.h. In the gtest
compilation context there is no config.h in path, but it uses WTF and
JSC files nevertheless, and some of these actually check for
configuration flags:

#include 
#include 
#include 
#include 
#include 



There are a few things all config.h files agree:

* Include cmakeconfig.h if a CMake build is being used.
* Include wtf/FastMalloc.h.
* Include wtf/DisallowCType.h.

Other than that, the differences are mostly sub-project specific quirks
to get around compilation issues of the sub-project. The case of the
WebKit sub-project is a bit more worrying as it has many defaults for
flags there, but they would not be read from the context of other
sub-projects.

We should consider why we have several config.h files and if that makes
sense or there are better alternatives. In principle, since config.h is
about configuration flags, and there is a single global set of flags for
the entire project, it would make much more sense to have a single true
config.h instead of sub-project-specific ones.

Re: [webkit-dev] What's the rationale for not including config.h in any header files?

2017-08-01 Thread Alicia Boya García
On 07/31/2017 11:16 PM, Maciej Stachowiak wrote:
> 
> 
>> On Jul 31, 2017, at 5:04 PM, Michael Catanzaro  wrote:
>>
>> On Mon, Jul 31, 2017 at 9:27 PM, Darin Adler  wrote:
>>> I don’t think we should add lots of includes of “config.h”, though. I think 
>>> we can come up with something better.
>>
>> Like what? The only alternative is to pass defines as preprocessor flags via 
>> -D. Our command lines are already hard enough to read as it is. Or, well, we 
>> could include config.h in Platform.h, where the ENABLE/USE series of macros 
>> are defined.
>>
>> I'm curious as to why including config.h in the header file would break 
>> Autotools builds. I don't see why that would be the case. As far as I know, 
>> it just happens to be common practice to include config.h only in source 
>> files. It's special: you always include it first in source files to avoid 
>> extremely confusing bugs that can result from not doing so, and therefore it 
>> seems redundant to put it in header files.
>>
>> I wonder how other projects (and other IDEs, e.g. XCode) handle this 
>> situation. Anyway, I don't have a strong opinion either way
> 
> I think "config.h" as the first body include, and never in headers, is mostly 
> just a stylistic choice in projects that use autotools.
> 
> However, here are some specific issues to consider:
> (1) Public API headers (or installed private interfaces) should not include 
> config.h, and should not rely on any macros defined there.
> (2) It's probably ok to include it in non-API headers, at least any that use 
> macros defined by config.h.
> (3) Implementation files may need to still include config.h. They might not 
> include any headers that include config.h, or they might currently but don't 
> want to rely on it. config.h may also define macros that affect the behavior 
> of system headers and therefore should be included before any of them, so it 
> needs to go first.
> (4) Given combo of (2) and (3), some includes of config.h in headers may be 
> redundant. I am not sure if this causes any practical problems though.
> 
>  - Maciej
> 
> ___
> webkit-dev mailing list
> webkit-dev@lists.webkit.org
> https://lists.webkit.org/mailman/listinfo/webkit-dev
> 

Regarding (1) and (2), the patch I'm proposing only modifies files that
use either USE() or ENABLED() macros. Since public API headers should
not depend on any compilation flags, they should not use either of these
and therefore they will not be modified by the patch.

I agree with (3). All WebKit .cpp files should still include "config.h".

Regarding (4), there should not be any problems as long as the config.h
files are guarded (either by #ifndef or #pragma once). Any effect on
build times should be minimal as the compilers resolve these guards very
quickly (and so far this has been true in my limited tests).

— Alicia.
___
webkit-dev mailing list
webkit-dev@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-dev


[webkit-dev] What's the rationale for not including config.h in any header files?

2017-07-31 Thread Alicia Boya García
Hi all.

The other day I noticed this in the Code Style Guidelines
(https://webkit.org/code-style-guidelines/#include-statements):

> Header files should never include config.h.

Is there a rationale for it?

config.h is a header file that pulls the compilation flags set in CMake,
some macro functions to query them plus some defaults for specific
platforms (e.g. if platform is Cocoa and WebRTC is enabled,
USE_LIBWEBRTC is defined automatically in WTF/wtf/Platform.h).

As of now, there are lots of instances of header files where macros such
as USE() or ENABLED() are used, yet config.h is not included (even
transitively) by that header file, thus breaking the "include what you
use" rule.

This is not a big deal for the compiler, as every .cpp file in the
project includes config.h before any other header, so by the time those
usages are really compiled those macros will be already defined.

On the other hand, static analysis tools, such as those in IDEs may not
be able to notice this. Unlike compilers, editors and human programmers
often treat files as independent units. For instance, in an editor you
open "LibWebRTCAudioCaptureSource.h", not "LibWebRTCAudioCaptureSource.h
as included by LibWebRTCAudioCaptureSource.cpp in line 28".

Ultimately this can be blamed to C++ fault because includes are a really
sloppy way to require dependencies, but I think we can agree that we
want headers to work as if they were independent units most of the time.

I've seen this issue manifest in QtCreator, as the IDE grays out all the
code inside #if USE() blocks as these macros are not defined or the
expressions inside evaluate to false in the context of that header file.

As an experiment to improve this situation, I first added #pragma once
in config.h files so that they can be included by any header file. Then,
I wrote a Python script that finds all usages of USE() and ENABLED()
macros in header files and adds a #include "config.h" where required.
Objective C headers are ignored by the script using some heuristics.

I built webkitgtk successfully both with and without the patch in gcc
and did not found any noticeable increase in compilation time: the
#pragma once guard is very fast, as expected, so that cannot be ruled as
a reason against. The result is the same but with better static analysis.

As the guidelines are right now I can't get this patch upstream because
they forbid from including config.h... but at least I would like to know
if there a compelling reason for them doing so.

(I attached the patch for the script and a few small edits needed so
that the includes work in all compilation contexts. More edits may be
needed in order for it to build in other platforms, but I could not test
that.)

Regards,
Alicia.
diff --git a/Source/JavaScriptCore/config.h b/Source/JavaScriptCore/config.h
index 1bd9d09741b..2203f266085 100644
--- a/Source/JavaScriptCore/config.h
+++ b/Source/JavaScriptCore/config.h
@@ -19,11 +19,13 @@
  *
  */
 
+#pragma once
+
 #if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
 #include "cmakeconfig.h"
 #endif
 
-#include "JSExportMacros.h"
+#include "runtime/JSExportMacros.h"
 
 #ifdef __cplusplus
 #undef new
diff --git a/Source/WTF/config.h b/Source/WTF/config.h
index ddc4f102190..58eeb534544 100644
--- a/Source/WTF/config.h
+++ b/Source/WTF/config.h
@@ -19,6 +19,8 @@
  *
  */
 
+#pragma once
+
 #if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
 #include "cmakeconfig.h"
 #endif
diff --git a/Source/WTF/wtf/glib/GTypedefs.h b/Source/WTF/wtf/glib/GTypedefs.h
index 51053c03d86..3f0610056b0 100644
--- a/Source/WTF/wtf/glib/GTypedefs.h
+++ b/Source/WTF/wtf/glib/GTypedefs.h
@@ -20,6 +20,11 @@
 #ifndef WTF_GTypedefs_h
 #define WTF_GTypedefs_h
 
+/* config.h cannot be included here from all contexts.
+ * For instance, this file is included transitively from ThirdParty/gtest/src/gtest.cc,
+ * which is compiled without any "config.h" in path. */
+#include 
+
 /* Vanilla C code does not seem to be able to handle forward-declaration typedefs. */
 #ifdef  __cplusplus
 
diff --git a/Tools/Scripts/include-config-where-needed.py b/Tools/Scripts/include-config-where-needed.py
new file mode 100755
index 000..fa7ed651df0
--- /dev/null
+++ b/Tools/Scripts/include-config-where-needed.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+import os
+import re
+import sys
+
+re_is_guard = re.compile(r'#if.*[^\w](ENABLE|USE)\s*\(')
+re_is_include = re.compile(r'^\s*#\s*include\s*[<"]config.h[>"]\s*')
+re_is_pragma_once = re.compile(r'^\s*#\s*pragma\s+once\s*')
+re_is_ifndef = re.compile(r'^s*#\s*ifndef\s.*')
+re_is_define = re.compile(r'^s*#\s*define\s.*')
+re_is_objc_import = re.compile('^s*#\s*import.*')
+re_is_objc_keyword = re.compile('^s*@\s*(class|interface|property|end)\s.*')
+
+
+def find_pragma_once_line(lines):
+return next((
+n_line
+for n_line, line in enumerate(lines)
+if re_is_pragma_once.match(line)
+), None)
+
+
+def find_tradi