mozilla / sccache

Sccache is a ccache-like tool. It is used as a compiler wrapper and avoids compilation when possible. Sccache has the capability to utilize caching in remote storage environments, including various cloud storage options, or alternatively, in local storage.
Apache License 2.0
5.74k stars 542 forks source link

Symbolic link doesn't seem to work on Linux #993

Open lackhoa opened 3 years ago

lackhoa commented 3 years ago

Using sccache-v0.2.15-x86_64-unknown-linux-musl, after symlinking:

$ ln -s sccache /usr/local/bin/gcc

I get this behavior

$ gcc
sccache: No command specified
sccache 0.2.15

USAGE:
    sccache [FLAGS] [OPTIONS] [cmd]...

FLAGS:
        --dist-auth       authenticate for distributed compilation
        --dist-status     show status of the distributed client
    -h, --help            Prints help information
    -s, --show-stats      show cache statistics
        --start-server    start background server
        --stop-server     stop background server
    -V, --version         Prints version information
    -z, --zero-stats      zero statistics counters

OPTIONS:
        --package-toolchain <executable> <out>    package toolchain for distributed compilation
        --stats-format <stats-format>
            set output format of statistics [default: text]  [possible values: text, json]

ARGS:
    <cmd>...    

Enabled features:
    S3:        true
    Redis:     true
    Memcached: true
    GCS:       true
    Azure:     true

sccache still thinks it is being called as sccache, and not as gcc.

The "wrap-around" behavior works fine before linking

$ sccache gcc
gcc: fatal error: no input files
compilation terminated.

But on my Mac, the same sccache v0.2.15 works fine with gcc being symlinked to sccache:

$ gcc
clang: error: no input files
lackhoa commented 3 years ago

Oh, I see that gcc was a symlink as well

$ ls -l /usr/bin/gcc
lrwxrwxrwx 1 root root 21 Dec 18 13:46 /usr/bin/gcc -> /etc/alternatives/gcc

Maybe that's why it didn't work?

Edit: I tried with a non-symlink compiler and it also didn't work, so that wasn't it.

lackhoa commented 3 years ago

If someone wants to reproduce this, I can offer this dockerfile

FROM ubuntu:bionic

# GCC 8
RUN apt-get install -y gcc-8 g++-8

# Use GCC 8 by default (https://askubuntu.com/questions/1028601/)
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 \
                        --slave   /usr/bin/g++ g++ /usr/bin/g++-8

# sccache
RUN export SCCACHE_VER=sccache-v0.2.15-x86_64-unknown-linux-musl && \
    wget https://github.com/mozilla/sccache/releases/download/v0.2.15/${SCCACHE_VER}.tar.gz && \
    tar -xzvf ${SCCACHE_VER}.tar.gz && \
    rm ${SCCACHE_VER}.tar.gz && \
    mv ${SCCACHE_VER}/sccache /usr/local/bin && \
    rm -rf ${SCCACHE_VER} && \
    chmod +x /usr/local/bin/sccache && \
    ln -s sccache /usr/local/bin/gcc && \
    ln -s sccache /usr/local/bin/g++ && \
    ln -s sccache /usr/local/bin/cc && \
    ln -s sccache /usr/local/bin/c++

I tried on a more complicated image, but this is what I believe to be the relevant parts. The result might be different from yours.

xanderificnl commented 3 years ago

The problem is due to symbolic links. Create hardlinks, i.e.:

ln /usr/local/bin/sccache /usr/local/bin/c++
ln /usr/local/bin/sccache /usr/local/bin/c99-gcc
ln /usr/local/bin/sccache /usr/local/bin/g++
ln /usr/local/bin/sccache /usr/local/bin/gcc
ln /usr/local/bin/sccache /usr/local/bin/x86_64-linux-gnu-g++
ln /usr/local/bin/sccache /usr/local/bin/x86_64-linux-gnu-gcc
ln /usr/local/bin/sccache /usr/local/bin/c89-gcc
ln /usr/local/bin/sccache /usr/local/bin/cc
ln /usr/local/bin/sccache /usr/local/bin/g++-10
ln /usr/local/bin/sccache /usr/local/bin/gcc-10
ln /usr/local/bin/sccache /usr/local/bin/x86_64-linux-gnu-g++-10
ln /usr/local/bin/sccache /usr/local/bin/x86_64-linux-gnu-gcc-10
lackhoa commented 3 years ago

Thanks @xanderificnl for your solution! I do not use sccache anymore but when I do I'll definitely check out hard links.

AZMCode commented 2 years ago

Hello, there seems to be another issue...

I've done this and it worked flawlessly, however when explicitly calling sccache, for example using sccache c++ ..., sccache will attempt to use the hardlink... which is itself, and thus the compiler doesn't work.

Of course, one could simply write out the full path to the actual compiler sccache /usr/bin/c++ ..., but some build tools, ironically, have sccache support but don't fully resolve the compiler path, meaning that this solution doesn't quite work.

Is there a way we could detect this setup and fix it? Perhaps checking if the compiler is a hardlink to the executable, then keep searching for another compiler if it isn't?

xanderificnl commented 2 years ago

The environment in which sccache is executed prioritizes the hardlink over the actual compiler. The hardlinks shouldn't be in the $PATH of the build tools you're referring to. That causes the issue you've encountered.

It does seem (after a quick glance) that sccache does take into account some scenarios. I'm guessing sccache c++ (where c++ is a hardlink to sccache) didn't result in an infinite loop?

AZMCode commented 2 years ago

It didn't, instead it led to an error about the compiler not supporting the -E flag

In any case, using sccache with hardlinks perhaps shouldn't rule out regular use.

xanderificnl commented 2 years ago

That error isn't helpful at all, and I do agree, sccache findings itself (albeit w/ a different name) shouldn't prevent usage at all.

Your suggestion for sccache to compare its inode with the compiler it intends to executable would be a nifty way to work around this issue.

AZMCode commented 2 years ago

I currently don't have my desktop available, but I'll respond back tomorrow with the proper error traceback and perhaps a feature request if needed. Thank you for your time.

AZMCode commented 2 years ago

Well, I'm kind of a week late to my commitment, sorry for that. Here's a brief demonstration of what I mean, and the error thrown when calling the hardlinks as described above.

https://asciinema.org/a/FzTl704ETrhS4WGMSUVe0npv3