How to develop on macOS and compile on linux efficiently

25 Apr 2020

I write web program with c++ in my macbook, deploy in customer's linux server. So, I must compile my code in a linux virtual machine, then put the binary file to my customer's server via sftp. It's a trouble for me, I write a shell program to make it automatic.

How I do before

I have a virtual machine run CentOS7 in my MBP, if I need to complie my code, I follow the steps below:

1. Start virtual machine

2. Put code files to vm via sftp

3. Login the vm and execute make command

4. Put binary files to target server via sftp on vm

5. Login target server and deploy the project

Sometimes I need to execute many times one day, for fix bug, update program and customer's wonderfull needs, and I have to switch between three system(my macOS, linux vm, target server). It become a nightmare for repeated labor.

Automatically compile on Linux

This can be achieved through a shell program, and I need to solve 3 problems:

How to login Linux server without password

It's not really passwordless, just that it's not necessary to enter the password every time. SSH password-less login is the one of the best way to automate tasks(TecMint).

Step 1: Delete server in know_hosts

Open know_hosts file vim ~/.ssh/know_hosts, and delete the line about the server which need to password-less login, otherwise the following operations will not be effective.

Step 2: Create Generating RSA Key on macOS

ssh-keygen -t rsa

The terminal will ask for enter file path and password, just press Enter key without entering.

Step 3: Create .ssh directory on server

ssh -p ssh_port username@vm_server_ip mkdir -p .ssh

.ssh directory may already exist on the server, so use the parameter "-p" after mkdir.

The terminal will output some information and let you confirm, enter yes and press Enter key, then enter ssh login password.

Step 4: Upload Generating RSA Key to server and set permissions

cat .ssh/id_rsa.pub | ssh -p ssh_port username@vm_server_id 'cat >> .ssh/authorized_keys'

ssh -p ssh_port username@vm_server_id 'chmod 700 .ssh; chmod 640 .ssh/authorized_keys'

How to upload/download files to/from a server via sftp

Step 1: Define server's informations and work directory

1
# project name
2
pro_name=ims
3
# server configs
4
server=xzlib.com
5
user=libo
6
port=22
7
rootpath=/home/libo/$pro_name

Step 2: Define upload function

Sometimes I need to upload only partial directories or files, which can be judged the parameters.

1
function PutFiles() {
2
    # delete old directory and create a new one
3
    ssh -p $port $user@$server "rm -fr $rootpath && mkdir -p $rootpath"
4
    if [[ ! $1 ]] {
5
        # have no parameters, upload all files
6
        echo "put -r * $rootpath" | sftp -P $port $user@$server
7
    } elif [[ -f $1 ]] {
8
        # have a parameter and it's a file, upload the file
9
        echo "put $1 $rootpath/$1" | sftp -P $port $user@$server
10
    } else {
11
        # have a parameter and it's a directory, upload the directory
12
        echo "put -r $1/* $rootpath/$1" | sftp -P $port $user@$server
13
    }
14
}

Step 3: Define download function

Only download deploy directory from virtual machine.

1
function GetFiles() {
2
    echo "get -r $rootpath/dep" | sftp -P $port $user@$server
3
}

How to compile on linux

When upload all files to virtual machine, the Makefile is also in it, just execute make command.

1
function MakeOnVirtual() {
2
    ssh -p $port $user@$server "cd $rootpath; make clean && make && make dep"
3
}

All the shell program codes

There is two server, the vritual machine for compile, the customer's server for deploy. I define vserver, vuser, vport, and vrootpaththe for virtual machine, server, user, port, and rootpath for customer's server. Both them hava the same project name.

1
#!/bin/zsh
2
# project name
3
pro_name=ims
4
# virtual server configs
5
vserver=127.0.0.1
6
vuser=libo
7
vport=22
8
vrootpath=/home/$vuser/$pro_name
9
# server configs
10
server=xzlib.com
11
user=libo
12
port=22
13
rootpath=/var/www/html/$pro_name
14
# upload files to virtual server
15
function Put2Virtual() {
16
    ssh -p $vport $vuser@$vserver "rm -fr $vrootpath && mkdir -p $vrootpath"
17
    if [[ ! $1 ]] {
18
        echo "put -r * $vrootpath" | sftp -P $vport $vuser@$vserver
19
    } elif [[ -f $1 ]] {
20
        echo "put $1 $vrootpath/$1" | sftp -P $vport $vuser@$vserver
21
    } else {
22
        echo "put -r $1/* $vrootpath/$1" | sftp -P $vport $vuser@$vserver
23
    }
24
}
25
# make on virtual server
26
function MakeOnVirtual() {
27
    ssh -p $vport $vuser@$vserver "cd $vrootpath; make clean && make && make dep"
28
}
29
# download deploy files from virtual server
30
function DownDeploy() {
31
    rm -fr dep
32
    echo "get -r $vrootpath/dep" | sftp -P $vport $vuser@$vserver
33
}
34
# upload deploy files to customer's server, set permissions, and restart apache
35
function DeployOnServer() {
36
    (echo "put -r dep/* $rootpath" && echo "chmod 777 $rootpath/log" && echo "chmod 777 $rootpath/tmp" && echo "chmod 777 $rootpath/res/upload") | sftp -P $port $user@$server
37
    ssh -p $port root@$server "systemctl restart httpd"
38
}
39
if [[ "$1" == "put" ]] {
40
    Put2Virtual $2
41
} elif [[ "$1" == "makel" ]] {
42
    Put2Virtual $2
43
    MakeOnVirtual
44
    DownDeploy
45
} elif [[ "$1" == "dep" ]] {
46
    DeployOnServer
47
}

How to use

I have two way to use it, in terminal or in vim.

In terminal

The shell named manage, if I want only upload all files to virtual machine, I can execute command ./manage put in terminal.

Other functions can execute the following commands:

./manage put src upload src files to virtual machine.

./manage put config upload config file to virtual machine.

./manage makel upload all files, compile on linux virtual machine, and download deploy files.

./manage dep upload deploy files to customer's server

In vim

I am used to programming with vim, and I don't like switch between vim and terminal. I configured the ~/.vimrc file, add the following:

1
" Save and Make on local macOS
2
command M call M()
3
function! M()
4
    exec "w"
5
    exec "!make"
6
endfunc
7
" Save and Make on linuxe virtual machine
8
command ML call ML()
9
function! ML()
10
    exec "w"
11
    exec "!make linux"
12
endfunc

There are such lines in my Makefile:

1
.PHONY : linux
2
linux:
3
./manage makel

When I want to compile on macOS and test the program, I execute :M, when I want to compile on linux, I execute :ML in vim.

Yeah! ML, are you crooked, it's means Make on Linux!