ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

It’s Time To Do CMake Right

Not so long ago I got the task of rethinking our build system. The idea was to evaluate existing components, dependencies, but most importantly, to establish a superior design by making use of modern CMake features and paradigms. Most people I know would have avoided such enterprise at all costs, but there is something about writing find modules that makes my brain release endorphins. I thought I was up for an amusing ride. Boy was I wrong.

My excitement was soon shattered after discovering the lack of standard practices in CMake usage and specially the insufficient adoption of modern design patterns. This post explores the concepts of what is known as modern CMake, which advocates for abandoning a traditional variable-based approach for a more structured model based on so-called targets. My intention is to show how β€œnew” (>= 3.0.0) features can be employed to reshape your CMake system into a more maintainable and intuitive alternative that actually makes sense.

Many of the concepts presented here find their roots in Daniel Pfeifer’s masterpiece Effective CMake. Daniel has practically become the Messiah of the modern CMake church, preaching best practices and guidelines in a time when the only standard is to not have one. Daniel, I am your prophet.

Enough preambles. Does this look familiar to you?

Don’t. Just don’t. This is wrong in so many dimensions. You are just blindly throwing stuff into a pot of include directories and compiler flags. There is no structure. There is no transparency. Not to mention that functions like include_directories work at the directory level and apply to all entities defined in scope.

And this isn’t even the real problem, what do you do with transitive dependencies? What about the order of linking? Yes, you need to take care about that yourself. The moment you need to deal with the dependencies of your dependencies is the moment your life needs to be reevaluated.

Targets and Properties

CMake developers saw the aforementioned problems and introduced language features that allow you to better structure your projects. Modern CMake is all about targets and properties. Conceptually this isn’t complicated. Targets model the components of you application. An executable is a target, a library is a target. Your application is built as a collection of targets that depend on and use each other.

Targets have properties. Properties of a target are the source files it’s built from, the compiler options it requires, the libraries it links against. In modern CMake you create a list of targets and define the necessary properties on them.

Build Requirements vs Usage Requirements

Target properties are defined in one of two scopes: INTERFACE and PRIVATE. Private properties are used internally to build the target, while interface properties are used externally by users of the target. In other words, interface properties model usage requirements, whereas private properties model build requirements of targets.

Interface properties have the prefix, wait for it, INTERFACE_ prepended to them.

Properties can also be specified as PUBLIC. Public properties are defined in both PRIVATE and INTERFACE scopes.

All of this is better understood with an example.

libjsonutils

Imagine that you are writing a json utily library, libjsonutils, that parses json files from a provided location. Json files can be located on your local file system, as well as accessible via some URL.

The library has the following structure:

We have a single public header, were we define the loadJson() function:

This function receives either a URL or a filepath to a json and loads it as a rapidjson object. If something goes wrong, boost::none will be returned instead.

Let’s start writing jsonutil’s CMakeLists.txt :

Nothing surprising here. The first step is to create our library target:

Now let’s define some properties on our target. Why not start with the include directories?

Leave CMAKE_CXX_FLAGS Alone

We can now continue by defining extra properties on our target. For example, it could be beneficial to treat warnings as errors:

Model dependencies with target_link_libraries

Let’s think about our dependencies. First off all, we need boost, as we use optional. Additionally, in order to figure out if the passed string is an URL, we have to evaluate it against some regex, so we need boost::regex (yes I know c++11 introduces regex utilities but bear with me). Second, we need rapidjson.

In CMake, target_link_libraries is used to model dependencies between targets.

Dependencies (a.k.a link libraries) of a target are just another property and are defined in an INTERFACE or PRIVATE scope. In our case, both rapidjson and boost optional (defined in the target Boost::boost ) have to be interface dependencies and be propagated to users, as they are used in a public header that’s imported by clients.

This means that users of JSONUtils don’t just require JSONUtil ’s interface properties, but also the interface properties of its interface dependencies (which define the public headers of boost and rapidjson in this case), and those of the dependencies of the dependencies, etc.

But how does CMake solve this problem? Easy, it adds all interface properties of Boost::boost and RapidJSON::RapidJSON to the corresponding JSONUtil ’s own interface properties. This means that users of JSONUtils will transitively receive the interface properties of targets all up the dependency chain.

On the other hand, Boost::regex is only used internally and can be a private dependency. Here, Boost::regexes interface properties will be appended to the corresponding JSONUtil ’s private properties, and won’t be propagated to users.

Isn’t this beautiful? Usage requirements are propagated and build requirements encapsulated. Welcome to modern CMake.

Sex, Drugs and Imported Targets

Note that Boost::boost and RapidJSON::RapidJSON are targets themselves. But where did they come from? I haven’t told you the most breathtaking fact about targets yet: targets can be exported. Exported targets can be later imported into other projects.

Our projects have structure, as they are build as a collection of encapsulated targets, and CMake handles transitive requirements for us. You might be wondering with tears in your eyes how beautiful life can be, but boy are up for a revelation.

Let’s try to build jsonutils:

Good boys export their targets

The imported target RapidJSON::RapidJSON could not be found, because RapidJSONConfig.cmake did not create it. Let’s inspect what rapidjson does in the config installed on my arch linux system:

Yes, welcome to hell. This is where the real pain begins: 3rdparty dependencies. In the case of rapidjson, a single variable is set to point to its include directories. This is exactly what we don’t want, we don’t want variables, we want targets!

In my case, 70% of my dependencies didn’t define any targets in their find modules or configs. The reality is that CMake usage is an anarchy. There are few rules and too much flexibility. We need standard practices, we need guidelines. We have design patterns for C++, why not for CMake?

If you want it done right do it yourself

So what can you do in these cases?

Daniel Pfeifer advises to report such usage as a bug to the library developers. I agree. Upstreams should support downstream’s modern target-based design. Ask yourself: do you really need this dependency? Are there alternatives that do support modern cmake usage?

In this case, however, there is no other option other taking matters into your own hands and write FindRapidJSON.cmake ourselves:

This is how you do CMake

We want jsonutils to integrate in a target-based build system of downstreams. This means that all they have to do to use jsonutils is this:

In CMake, installed targets are registered to exports using the EXPORT argument. Exports are therefore just a set of targets that can be exported and installed. Here we just told CMake to install our library and to register the target in the export jsonutils-export.

Then we can go ahead and install the export that we defined above:

This will install the import script JSONUtilsTargets.cmake that, when included in other scripts, will load the targets defined in the export jsonutils-export. By using the NAMESPACE argument, we tell CMake to prepend the prefix JSONUtils:: to all targets imported.

Import your targets inside your Config.cmake

So that our target JSONUtils::JSONUtils is imported and can be used by clients, we need to load JSONUtilsTargets.cmake in our config file:

Be aware that JSONUtilsTargets.cmake contains code like:

That’s all folks

You can refer to my github where I have uploaded the entire jsonutils project containing all the code shown in this post. There I also included examples on how to test the library using gtest, as well as how to export your targets from the build tree and register them in CMake’s package registry.

Hopefully by now you were able to grasp how clean and structured a target-based CMake can be compared to a flag and variable based approach. Also, exporting your targets is something your grandma could do, so why not do it? I believe the reason is that CMake suffers from a syndrome of β€œif no one does it why should I?” We need to change this. We deserve to live in a better world. Export your targets goddammit.

About

This blog explores a variety of topics that I’ve stumbled across in my journey as a software developer. Even though mostly written for my own understanding, my hope is that the curious programmer finds my writings entertaining.

Β© 2021. All rights reserved.

Pablo Arias

Personal blog about the little stuff I know

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ

You must set the Minecraft Version!

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

GoogleTan

ΠšΠ°Ρ€Ρ‚ΠΎΡˆΠΊΠ° :3

Intellij idea странно ругаСтся Π½Π° Π²Π΅Ρ€ΡΠΈΡŽ ΠΌΡ†:

‘C:\forge-1.7.10-10.13.4.1614-1.7.10-src\build.gradle’ line: 19 A problem occurred evaluating root project ‘forge-1.7.10-10.13.4.1614-1.7.10-src’. > Failed to apply plugin [id ‘forge’] > You must set the Minecraft Version! > java.lang.NullPointerException (no error message)
Build file

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

ZZZubec

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

Π·Π°Ρ‚Π΅ΠΌ ΠΊΠ°ΠΊ загрузится ТмСшь

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

ΠΎΠ½ ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚ ΠΎΠΊΠ½ΠΎ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π²Ρ‹Π±Π΅Ρ€Π΅ΡˆΡŒ 1.8 (ΠΎΠ½Π° ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ ΡƒΠΆΠ΅ Π΄ΠΎΠ»ΠΆΠ½Π° ΡΡ‚ΠΎΡΡ‚ΡŒ, Π½Ρƒ ΠΈΠ»ΠΈ 7ΠΊΡƒ)

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

я Π²Ρ‹Π±Ρ€Π°Π» jre, Π½ΠΎ ΠΎΠ½ ΠΏΠΎΡ‡Π΅ΠΌΡƒ Ρ‚ΠΎ всё Ρ€Π°Π²Π½ΠΎ Π΅Ρ‘ схавал ΠΈ Π·Π°Ρ€Π°Π±ΠΎΡ‚Π°Π»

Он пСрСзапустит IntelliJ, Π½Π° это Π½Π΅ ΠΎΠ±Ρ€Π°Ρ‰Π°ΠΉ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ (хотя моТСшь ΠΈ Π½Π°ΠΆΠ°Ρ‚ΡŒ, это Π½Π΅ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΈΠ°Π»ΡŒΠ½ΠΎ я Π΄ΡƒΠΌΠ°ΡŽ)

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

Ну ΠΈ Π½Π°ΠΊΠΎΠ½Π΅Ρ† ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ Π½Π° Π²ΠΊΠ»Π°Π΄ΠΊΡƒ Gradle, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ всё ΠΏΡƒΡ‡ΠΊΠΎΠΌ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ

GNU make

June 23rd, 2000 (updated July 4th, 2020)

This document describes a very useful method for having make itself create and maintain these dependencies completely automatically.

All make programs must know, with great accuracy, what files a particular target is dependent on in order to ensure that it is rebuilt when (and only when) necessary.

Keeping this list up-to-date by hand is not only tedious, but quite error prone. Most systems of any size prefer to provide automated tools for extracting this information. The traditional tool was the makedepend program, which reads C source files and generates a list of the header files in a target-dependency format suitable for inclusion in (or appending to) a makefile.

The modern solution, for those using suitably enlightened compilers or preprocessors (such as GCC), is to have the compiler or preprocessor generate this information.

The purpose of this paper isn’t primarily to discuss ways in which this dependency information can be obtained, although this is covered. Rather, it describes some useful ways to combine the invocation and output of these tools with GNU make to ensure that dependency information is always accurate and up-to-date, as seamlessly (and efficiently) as possible.

TL;DR: The GCC Solution

For those who are impatient, here’s a complete best-practice solution. This solution requires support from your compiler: it assumes you are using GCC as your compiler (or a compiler which provides preprocessor flags compatible with GCC). If your compiler doesn’t meet this criteria, keep reading for alternatives.

Add this to your makefile environment (the sections in blue are the changes to the built-in content provided by GNU make). Of course you can omit pattern rules which don’t fit your environment (or add new ones as needed):

Be aware that the include line must come after the initial, default target; otherwise the included dependency files will abscond with your default target setting. It’s fine to add this to the very end of your makefile (or, keep it in a separate makefile and include it).

Also, this assumes the SRCS variable contains all the source files (not header files) you want to track dependencies for.

Traditional make depend Method

If your version of make supports include you can redirect this to a file and simply include the file. If not, this usually also involves some shell hackery to append the list of dependencies generated to the end of the makefile itself.

Although it’s simple, there are serious problems with this method. First and foremost is that dependencies are only rebuilt when the user explicitly requests it; if the user doesn’t run make depend regularly they could become badly out-of-date and make will not properly rebuild targets. Thus, we cannot say this is seamless and accurate.

So, we’ll see how we can do better.

The GNU make include Directive

Most versions of make support some sort of include directive (and indeed, include is required by the latest POSIX specification). Unsurprisingly, this allows one makefile to include other makefiles, as if they had been entered there.

One can immediately see how this would be useful, simply to avoid appending dependency information to a makefile as in the step above. However, there is a more interesting capability in GNU make β€˜s handling of include : just as with the normal makefile, GNU make will attempt to rebuild the included makefile. If it is successfully rebuilt, GNU make will re-execute itself to read the new version.

This auto-rebuild feature can be harnessed to avoid requiring a separate make depend step: if you list all the source files as prerequisites to the file containing dependency information, then include that file into your makefile, it will be rebuilt every time a source file changed. As a result, the dependency information will always be up-to-date and the user doesn’t need to run make depend explicitly.

Of course, this means dependency information is recalculated for all files every time any file changes, which is unfortunate. We can still do better than this.

For a detailed description of GNU make β€˜s automatic rebuild feature, see the GNU make User’s Manual, section β€œ How Makefiles Are Remade ”.

Basic Auto-Dependencies

These dependency files are then all included by the makefile. An implicit rule is provided that describes how the dependency files are to be created. In short, something like this:

What is the format of the generated dependency file? In this simple case, we need to declare that both the object file and the dependency file have the same set of prerequisites: the source file and all the header files. So a foo.d file might contain this:

Here we solve the two problems with the earlier solutions. First, the user doesn’t have to do anything special to ensure accurate dependency lists; make will take care of it. Second, we are only updating dependency lists for those file which have actually changed, not all the files in the directory.

We have three new problems with this method, however. The first is still efficiency. Although we only re-examine changed files we still will re-exec make if anything changes, which could be slow for large build systems.

Advanced Auto-Dependencies

Avoiding Re-exec of make

Since we don’t need the up-to-date prerequisite list in this build, we can actually avoid re-invoking make at all: we can simply have the prerequisite list built at the same time as the target is rebuilt. In other words, we can change the build rule for our target to add in commands to update the dependency file.

In this case we must be very careful that we don’t provide rules to build the dependencies automatically: if we do make will still try to rebuild them and re-exec: we don’t want that.

Now that we don’t care about dependency files that don’t exist, solving the second problem (superfluous warnings) is easy: we can just use GNU make β€˜s wildcard function so that dependency files which don’t exist won’t cause an error.

Let’s take a look at an example so far:

Avoiding β€œNo rule to make target …” Errors

This one is a little trickier. However, it turns out we can convince make to not fail merely by mentioning the file explicitly as a target in the makefile. If a target exists, but has no commands (either implicit or explicit) or prerequisites, then make simply always considers it up-to-date. That’s the normal case, and it behaves as we’d expect.

In the case where the above error occurs, the target doesn’t exist. According to the GNU make User’s Manual section Rules without Recipes or Prerequisites :

If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then `make’ imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipes run.

Perfect. It ensures make won’t throw an error since it knows how to handle that non-existent file, and it ensures that any file depending on that target is rebuilt, which is exactly what we want.

So, all we need to do is modify the dependency file output so that each prerequisite (source and header file) are defined as targets with no commands or prerequisites. So the output of our MAKEDEPEND script would generate a foo.d file something like this:

Handling Deleted Dependency Files

There is one remaining issue with this configuration: if a user happens to delete dependency files without modifying any of the source files, make will not notice anything amiss and will not recreate the dependency files until it decides to rebuild the corresponding object file for some other reason. In the meantime make will be missing dependency information for those targets (so, for example, modifying a header file without changing the source file will not cause the object file to be rebuilt).

The problem is slightly complex because we do not want the dependency files to be considered β€œreal” targets: if they are then when we use include to include them, make will rebuild them then re-exec itself. This isn’t the end of the world, but it’s overhead we’d prefer to do without.

The automake method doesn’t address this problem. In the past I’ve suggested a β€œjust don’t do that” solution, combined with placing dependency files in a separate directory to make it difficult to accidentally delete them.

However, Lukas Waymann suggested a tidy solution: add the dependency file as a prerequisite to the target, and create an empty recipe for it:

This solves the problem nicely: when make checks the target it will see the dependency file as a prerequisite and try to build that. If it exists nothing will be done since there’s no prerequisites for the dependency file. If it doesn’t exist, it will be marked out of date since it has an empty recipe, which will force the object target to be rebuilt (creating a new dependency file).

When make is trying to rebuild included files it will find the implicit rule for the dependency and use it. However since the rule doesn’t update the target file, no included file was updated and make will not re-execute itself.

Placement of Output Files

Defining MAKEDEPEND

Here I’ll discuss some possible ways to define the MAKEDEPEND variable I’ve blithely been using above.

The most basic way to generate dependencies is by using the C preprocessor itself. This requires a bit of knowledge about the output format of your preprocessor–luckily most UNIX preprocessors have similar-enough output for our purposes. In order to preserve line number information for the compiler’s error messages and debugging information, the output of the preprocessor must provide line number and filename information for each jump to an #include file and each return from one. These lines can be used to figure out what files were included.

Most UNIX preprocessors insert special lines in the output with this format:

MAKEDEPEND = makedepend

Combining Compilation and Dependency Generation

One continuing issue above is that we need to preprocess the source file twice: once in the MAKEDEPEND command and then again as part of the compilation step.

If you’re using GCC (or a compiler which provides equivalent options) you can save yourself a lot of time during the build by combining the dependency generation and the object file generation into a single command, because these compilers have the ability to output the dependency information as a side-effect of the compilation. Here is an example implementation, copied from the TL;DR section at the top of this page:

Let’s go over the parts in blue, above, which are the differences from the standard make built-in rules:

Handling unusual situations

There have been reports of some problems with this solution in certain unusual situations:

You can fix both of these with some defensive coding in your makefile to harden it against problems. For example, something like:

Here we change DEPFLAGS to write to a temporary file, then add a POSTCOMPILE step, which is only run if the compilation succeeds, that renames the temporary file to the good file and finally, touches the object file to make sure it’s newer than the dependency file.

Placement of Object Files

Often you will want to put object files in a remote location as well, not just dependency files. Here’s a quick example of this:

Dependencies For Non-C Files

In general you need some way of producing dependency files in order to use these methods. If you’re working with files that aren’t C files you’ll need to discover or write your own method. Anything that generates make dependency files will do. This usually isn’t too difficult.

An interesting idea has been proposed by Han-Wen Nienhuys and he has a small β€œproof of concept” implementation, although it currently only works on Linux. He suggests using the LD_PRELOAD environment to insert special shared library that contains a replacement for the open (2) system call. This version of open() would actually write out make dependency information for every file the commands read during operation. This would give you completely reliable dependency information for every kind of command without needing any special dependency extraction tools at all. In his proof-of-concept implementation you can control the output file and exclude some kinds of files (shared libraries, maybe) via environment variables.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ

What is the right way to load dependencies in PHP?

I have a doubt about the right way/best practice about loading dependent classes in PHP.

I usually put all dependencies in the beginning of each class with a include_once in a way similar to Java imports. Something like:

Note that I’m talking about loading my own classes, not complex external classes like frameworks.

ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π‘ΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΡƒ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° ΠΏΡ€ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for. Π€ΠΎΡ‚ΠΎ ΠΌΠ°ΠΉΠ½ΠΊΡ€Π°Ρ„Ρ‚ you must include the right dependencies for

4 Answers 4

Since version 5.3 PHP supports namespaces. This allows you to have a package and class hierarchy just like you know them from C++ or Java.

Check out those resources to learn more:

PHP’s you can register your autoload method. Symfony 2 contains a nice class to do it with.

I’ve adapted it to work with the library that we’ve written.

This adaption allows you to have namespaces that do not require the top level namespace to have the same folder name.

Like Homer6 said, autoloading is a php’s built in dependency loading mechanism.

PHP-FIG proposed a family of PHP coding standards called PSR. PSR-0 deals with class naming and autoloading. Here are some links:

Also, keep in mind, that autoloading comes with a price. There is a lot of string work and work with the fs in the proposed default autoloader(you can implement your own faster autoloader, but it is not going to conform to the standard). This makes autoloading slow when you need to load a lot of classes. So if you needed to load 2 classes only, your approach would be faster and more understandable.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

Π’Π°Ρˆ адрСс email Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Π½. ΠžΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ поля ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½Ρ‹ *