compile concurrently, link seriallyWhy does the order in which libraries are linked sometimes cause errors in GCC?Embedding DLLs in a compiled executableHow to speed up c++ linking timeWhy does C++ linking use virtually no CPU?How does the compilation/linking process work?Linking errors when trying to compile FubiDoes C++ Builder linker support function-level linking?Difference between using Makefile and CMake to compile the codeCompiling an application for use in highly radioactive environments(Eclipse oxygen/Linux) linker C/C++ RAM usage
MAXDOP Settings for SQL Server 2014
Should I install hardwood flooring or cabinets first?
Drawing ramified coverings with tikz
A social experiment. What is the worst that can happen?
How do I repair my stair bannister?
How do ground effect vehicles perform turns?
Should I stop contributing to retirement accounts?
Global amount of publications over time
Why has "pence" been used in this sentence, not "pences"?
Could solar power be utilized and substitute coal in the 19th Century
What major Native American tribes were around Santa Fe during the late 1850s?
What is the grammatical term for “‑ed” words like these?
List of people who lose a child in תנ"ך
Is there a conventional notation or name for the slip angle?
On a tidally locked planet, would time be quantized?
Is a model fitted to data or is data fitted to a model?
Query about absorption line spectra
Is it possible to have a strip of cold climate in the middle of a planet?
Did arcade monitors have same pixel aspect ratio as TV sets?
Folder comparison
Indicating multiple different modes of speech (fantasy language or telepathy)
About a little hole in Z'ha'dum
What (else) happened July 1st 1858 in London?
Why did the EU agree to delay the Brexit deadline?
compile concurrently, link serially
Why does the order in which libraries are linked sometimes cause errors in GCC?Embedding DLLs in a compiled executableHow to speed up c++ linking timeWhy does C++ linking use virtually no CPU?How does the compilation/linking process work?Linking errors when trying to compile FubiDoes C++ Builder linker support function-level linking?Difference between using Makefile and CMake to compile the codeCompiling an application for use in highly radioactive environments(Eclipse oxygen/Linux) linker C/C++ RAM usage
I have big cmake/c++/linux project: a lot of small static libraries, a few big and interdependent static libraries, a few big executable binaries. Single binary with debug symbols is several GB. There are ~10 such binaries (worker, testA, testB, testC...). Compilation usually takes more time than we would like, but we have fast build server and we use make -j20. The worst though is linking. Single linking takes about 60 seconds and 4GB RAM. But when all final binaries are linked at the same time (happens often when 1 small sublibrary was modified, little to recompile, a lot to relink), 10 linkers use 40GB RAM (for 1 developer, there may be more) and very long time. IO is most likely the bottleneck.
We have many developers on 1 strong server and everybody uses make -j20 -l30 so that we don't overload CPU. But we don't have method for limiting number of concurrent linkers. It would be great to limit number of working linkers globally on server, but per make invocation would help as well. Ideally make -j20 -l30 --concurrent-linkers=2. Is it possible?
We use gold linker. We are in progress of separating smaller, independent modules, but this will take a long time.
c++ makefile cmake linker
|
show 1 more comment
I have big cmake/c++/linux project: a lot of small static libraries, a few big and interdependent static libraries, a few big executable binaries. Single binary with debug symbols is several GB. There are ~10 such binaries (worker, testA, testB, testC...). Compilation usually takes more time than we would like, but we have fast build server and we use make -j20. The worst though is linking. Single linking takes about 60 seconds and 4GB RAM. But when all final binaries are linked at the same time (happens often when 1 small sublibrary was modified, little to recompile, a lot to relink), 10 linkers use 40GB RAM (for 1 developer, there may be more) and very long time. IO is most likely the bottleneck.
We have many developers on 1 strong server and everybody uses make -j20 -l30 so that we don't overload CPU. But we don't have method for limiting number of concurrent linkers. It would be great to limit number of working linkers globally on server, but per make invocation would help as well. Ideally make -j20 -l30 --concurrent-linkers=2. Is it possible?
We use gold linker. We are in progress of separating smaller, independent modules, but this will take a long time.
c++ makefile cmake linker
2
The problem is thatmakeitself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.
– Some programmer dude
Mar 7 at 9:05
2
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
1
Are you restricted tomake? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK
– MSalters
Mar 7 at 13:44
|
show 1 more comment
I have big cmake/c++/linux project: a lot of small static libraries, a few big and interdependent static libraries, a few big executable binaries. Single binary with debug symbols is several GB. There are ~10 such binaries (worker, testA, testB, testC...). Compilation usually takes more time than we would like, but we have fast build server and we use make -j20. The worst though is linking. Single linking takes about 60 seconds and 4GB RAM. But when all final binaries are linked at the same time (happens often when 1 small sublibrary was modified, little to recompile, a lot to relink), 10 linkers use 40GB RAM (for 1 developer, there may be more) and very long time. IO is most likely the bottleneck.
We have many developers on 1 strong server and everybody uses make -j20 -l30 so that we don't overload CPU. But we don't have method for limiting number of concurrent linkers. It would be great to limit number of working linkers globally on server, but per make invocation would help as well. Ideally make -j20 -l30 --concurrent-linkers=2. Is it possible?
We use gold linker. We are in progress of separating smaller, independent modules, but this will take a long time.
c++ makefile cmake linker
I have big cmake/c++/linux project: a lot of small static libraries, a few big and interdependent static libraries, a few big executable binaries. Single binary with debug symbols is several GB. There are ~10 such binaries (worker, testA, testB, testC...). Compilation usually takes more time than we would like, but we have fast build server and we use make -j20. The worst though is linking. Single linking takes about 60 seconds and 4GB RAM. But when all final binaries are linked at the same time (happens often when 1 small sublibrary was modified, little to recompile, a lot to relink), 10 linkers use 40GB RAM (for 1 developer, there may be more) and very long time. IO is most likely the bottleneck.
We have many developers on 1 strong server and everybody uses make -j20 -l30 so that we don't overload CPU. But we don't have method for limiting number of concurrent linkers. It would be great to limit number of working linkers globally on server, but per make invocation would help as well. Ideally make -j20 -l30 --concurrent-linkers=2. Is it possible?
We use gold linker. We are in progress of separating smaller, independent modules, but this will take a long time.
c++ makefile cmake linker
c++ makefile cmake linker
edited Mar 7 at 9:21
Tsyvarev
27.6k43264
27.6k43264
asked Mar 7 at 8:58
MateuszLMateuszL
820819
820819
2
The problem is thatmakeitself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.
– Some programmer dude
Mar 7 at 9:05
2
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
1
Are you restricted tomake? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK
– MSalters
Mar 7 at 13:44
|
show 1 more comment
2
The problem is thatmakeitself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.
– Some programmer dude
Mar 7 at 9:05
2
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
1
Are you restricted tomake? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK
– MSalters
Mar 7 at 13:44
2
2
The problem is that
make itself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.– Some programmer dude
Mar 7 at 9:05
The problem is that
make itself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.– Some programmer dude
Mar 7 at 9:05
2
2
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
1
1
Are you restricted to
make? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK– MSalters
Mar 7 at 13:44
Are you restricted to
make? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK– MSalters
Mar 7 at 13:44
|
show 1 more comment
1 Answer
1
active
oldest
votes
You could try something like:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
And call it with:
$ make -j20 -l30 concurrent-linkers=2
Basically, it separates the build in two make invocations, one for compilation and one for link, with different -j options. The main drawback is that all compilations must be finished before the first link starts. A better solution would be to design a simple link job server (a simple shell script with a bit of flock and tag files would make it) and delegate it the link jobs. But if you can live with this...
Demo with a dummy Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...n' && sleep 2 && printf 'donen' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
As you can see all $(OBJS) targets are built in parallel while the $(EXES) targets are built 2 (maximum) at a time.
EDIT If your makefile is generated by CMake there are at least two options:
Tune your CMake files such that CMake generates two different makefiles: one for compilation and one for link. Then write a simple wrapper makefile like:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilationConvince CMake (if it is not already the case) to generate a makefile that defines two make variables: one (
OBJS) set to the list of all object files and one (EXES) set to the list of all executable. Then write a simple wrapper makefile like:.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)A very similar solution exists if, instead, CMake generates two phony targets, one for all object files and the other for all executable:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link
TheMakefilein the question is generated by CMake; this answer presumes a hand-rolled Makefile.
– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55039722%2fcompile-concurrently-link-serially%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could try something like:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
And call it with:
$ make -j20 -l30 concurrent-linkers=2
Basically, it separates the build in two make invocations, one for compilation and one for link, with different -j options. The main drawback is that all compilations must be finished before the first link starts. A better solution would be to design a simple link job server (a simple shell script with a bit of flock and tag files would make it) and delegate it the link jobs. But if you can live with this...
Demo with a dummy Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...n' && sleep 2 && printf 'donen' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
As you can see all $(OBJS) targets are built in parallel while the $(EXES) targets are built 2 (maximum) at a time.
EDIT If your makefile is generated by CMake there are at least two options:
Tune your CMake files such that CMake generates two different makefiles: one for compilation and one for link. Then write a simple wrapper makefile like:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilationConvince CMake (if it is not already the case) to generate a makefile that defines two make variables: one (
OBJS) set to the list of all object files and one (EXES) set to the list of all executable. Then write a simple wrapper makefile like:.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)A very similar solution exists if, instead, CMake generates two phony targets, one for all object files and the other for all executable:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link
TheMakefilein the question is generated by CMake; this answer presumes a hand-rolled Makefile.
– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
add a comment |
You could try something like:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
And call it with:
$ make -j20 -l30 concurrent-linkers=2
Basically, it separates the build in two make invocations, one for compilation and one for link, with different -j options. The main drawback is that all compilations must be finished before the first link starts. A better solution would be to design a simple link job server (a simple shell script with a bit of flock and tag files would make it) and delegate it the link jobs. But if you can live with this...
Demo with a dummy Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...n' && sleep 2 && printf 'donen' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
As you can see all $(OBJS) targets are built in parallel while the $(EXES) targets are built 2 (maximum) at a time.
EDIT If your makefile is generated by CMake there are at least two options:
Tune your CMake files such that CMake generates two different makefiles: one for compilation and one for link. Then write a simple wrapper makefile like:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilationConvince CMake (if it is not already the case) to generate a makefile that defines two make variables: one (
OBJS) set to the list of all object files and one (EXES) set to the list of all executable. Then write a simple wrapper makefile like:.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)A very similar solution exists if, instead, CMake generates two phony targets, one for all object files and the other for all executable:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link
TheMakefilein the question is generated by CMake; this answer presumes a hand-rolled Makefile.
– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
add a comment |
You could try something like:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
And call it with:
$ make -j20 -l30 concurrent-linkers=2
Basically, it separates the build in two make invocations, one for compilation and one for link, with different -j options. The main drawback is that all compilations must be finished before the first link starts. A better solution would be to design a simple link job server (a simple shell script with a bit of flock and tag files would make it) and delegate it the link jobs. But if you can live with this...
Demo with a dummy Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...n' && sleep 2 && printf 'donen' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
As you can see all $(OBJS) targets are built in parallel while the $(EXES) targets are built 2 (maximum) at a time.
EDIT If your makefile is generated by CMake there are at least two options:
Tune your CMake files such that CMake generates two different makefiles: one for compilation and one for link. Then write a simple wrapper makefile like:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilationConvince CMake (if it is not already the case) to generate a makefile that defines two make variables: one (
OBJS) set to the list of all object files and one (EXES) set to the list of all executable. Then write a simple wrapper makefile like:.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)A very similar solution exists if, instead, CMake generates two phony targets, one for all object files and the other for all executable:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link
You could try something like:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
And call it with:
$ make -j20 -l30 concurrent-linkers=2
Basically, it separates the build in two make invocations, one for compilation and one for link, with different -j options. The main drawback is that all compilations must be finished before the first link starts. A better solution would be to design a simple link job server (a simple shell script with a bit of flock and tag files would make it) and delegate it the link jobs. But if you can live with this...
Demo with a dummy Makefile:
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...n' && sleep 2 && printf 'donen' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
As you can see all $(OBJS) targets are built in parallel while the $(EXES) targets are built 2 (maximum) at a time.
EDIT If your makefile is generated by CMake there are at least two options:
Tune your CMake files such that CMake generates two different makefiles: one for compilation and one for link. Then write a simple wrapper makefile like:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilationConvince CMake (if it is not already the case) to generate a makefile that defines two make variables: one (
OBJS) set to the list of all object files and one (EXES) set to the list of all executable. Then write a simple wrapper makefile like:.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)A very similar solution exists if, instead, CMake generates two phony targets, one for all object files and the other for all executable:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: cmake-target-for-compilation
$(MAKE) -j $(concurrent-linkers) cmake-target-for-link
edited Mar 7 at 14:44
answered Mar 7 at 12:35
Renaud PacaletRenaud Pacalet
9,60821731
9,60821731
TheMakefilein the question is generated by CMake; this answer presumes a hand-rolled Makefile.
– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
add a comment |
TheMakefilein the question is generated by CMake; this answer presumes a hand-rolled Makefile.
– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
The
Makefile in the question is generated by CMake; this answer presumes a hand-rolled Makefile.– MSalters
Mar 7 at 13:40
The
Makefile in the question is generated by CMake; this answer presumes a hand-rolled Makefile.– MSalters
Mar 7 at 13:40
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
MSalters is correct - is it possible to do with CMake?
– MateuszL
Mar 7 at 14:06
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
If you can use CMake to generate two makefiles, one for compilation and one for link, then yes, it is possible (and easy). Else, you must find a way to tell CMake that you want a makefile that defines a make variable set to all object files and another set to all executable. You will then simply include this CMake-generated makefile in a wrapper makefile that does more or less what I suggest in my examples.
– Renaud Pacalet
Mar 7 at 14:19
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55039722%2fcompile-concurrently-link-serially%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
The problem is that
makeitself doesn't really know what's happening, all it does is execute commands without knowing what the commands are really doing.– Some programmer dude
Mar 7 at 9:05
2
As a possible workaround you could use two targets: One for compilation and one for linking. The compilation target is run using high parallelization and the linking target without.
– Some programmer dude
Mar 7 at 9:05
I might be missing the point. Using less linkers isn't going to make linking faster, is it? You'll get the first output quicker, but the last link will start much later and finish at the same time as before (assuming you do have enough RAM, of course).
– MSalters
Mar 7 at 10:01
@MSalters We have basically thin clients to central server. When linkers start abusing server, nobody can work due to overloaded IO. Secondly, we have 2nd server with less RAM - it can compile -j30 no problem, but linking -j4 causes OOM killer
– MateuszL
Mar 7 at 13:39
1
Are you restricted to
make? CMake can also target Ninja, and Ninja supports JOB_POOL_LINK– MSalters
Mar 7 at 13:44