Skip to content

Commit fe10bd2

Browse files
committed
Initial commit
0 parents  commit fe10bd2

File tree

11 files changed

+307
-0
lines changed

11 files changed

+307
-0
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/

Diff for: Dockerfile

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Dockerfile to build sine and libsndfile for Amazon Linux 2.
2+
#
3+
# To build:
4+
# docker build -t sine .
5+
#
6+
# To copy the binaries to the host system, run:
7+
# docker create --name sine-build sine:latest
8+
# docker cp sine-build:/usr/local/lib64/libsndfile.so.1.0.29 .
9+
# docker cp sine-build:/usr/local/lib64/libsndfile.so.1 .
10+
# docker cp sine-build:/usr/local/lib64/libsndfile.so .
11+
# docker cp sine-build:/opt/sine/insta//bin/sine .
12+
# docker rm sine-build
13+
#
14+
15+
FROM amazonlinux:2.0.20200406.0
16+
17+
RUN \
18+
yum -q -y groupinstall "Development Tools"
19+
20+
RUN \
21+
yum -q -y install \
22+
cmake3 \
23+
ninja-build \
24+
&& ln -s /usr/bin/cmake3 /usr/bin/cmake
25+
26+
# Build and install libsndfile. Compile as a shared library to conform to LGPL.
27+
#
28+
# libsndfile-devel 1.0.25 is available through the package manager, but that
29+
# version doesn't provide a CMake package configuration file. Therefore, build a
30+
# more recent version.
31+
# TODO: Update when https://github.com/erikd/libsndfile/pull/524 is merged.
32+
ENV LIBSNDFILE_GIT_REF c103c16c972c3c30197ef0da963802ce7c33ad72
33+
ENV LIBSNDFILE_TARBALL_SHA256 17a43830e869987ae2dca7839363f7317b6ce00dfe161d507ef0b73ccc6b4c42
34+
WORKDIR /opt/libsndfile
35+
RUN \
36+
curl -L https://api.github.com/repos/msmolens/libsndfile/tarball/${LIBSNDFILE_GIT_REF} > libsndfile.tar.gz && \
37+
echo "$LIBSNDFILE_TARBALL_SHA256 libsndfile.tar.gz" | sha256sum -c -w --status - && \
38+
mkdir libsndfile && \
39+
tar zxf libsndfile.tar.gz --strip-components=1 && \
40+
mkdir build && \
41+
cd build && \
42+
cmake -G Ninja \
43+
-DCMAKE_BUILD_TYPE:STRING=Release \
44+
-DBUILD_SHARED_LIBS:BOOL=ON \
45+
-DBUILD_PROGRAMS:BOOL=OFF \
46+
-DBUILD_TESTING:BOOL=OFF \
47+
-DENABLE_EXTERNAL_LIBS:BOOL=OFF \
48+
.. && \
49+
cmake --build . --target install
50+
51+
# Build and install the example sine program.
52+
ENV INSTALL_PREFIX /opt/sine/install
53+
WORKDIR /opt/sine/build
54+
COPY sine .
55+
RUN mkdir build && \
56+
cd build && \
57+
cmake -G Ninja \
58+
-DCMAKE_BUILD_TYPE=Release \
59+
-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
60+
.. && \
61+
cmake --build . --target install && \
62+
echo "Shared libraries:" && \
63+
ldd ${INSTALL_PREFIX}/bin/sine && \
64+
strip ${INSTALL_PREFIX}/bin/sine

Diff for: LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Max Smolens
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Diff for: Makefile

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Makefile to build sine and libsndfile for Amazon Linux 2.
2+
3+
IMAGE = sine
4+
NAME = sine-build
5+
OUTDIR = ./build
6+
7+
.PHONY: all
8+
9+
all: copy
10+
11+
build: Dockerfile
12+
docker build -t $(IMAGE) -f Dockerfile .
13+
14+
copy: build
15+
mkdir -p $(OUTDIR)
16+
docker create --name $(NAME) $(IMAGE)
17+
docker cp $(NAME):/usr/local/lib64/libsndfile.so.1.0.29 $(OUTDIR)
18+
docker cp $(NAME):/usr/local/lib64/libsndfile.so.1 $(OUTDIR)
19+
docker cp $(NAME):/usr/local/lib64/libsndfile.so $(OUTDIR)
20+
docker cp $(NAME):/opt/sine/install/bin/sine $(OUTDIR)
21+
docker rm $(NAME)
22+
23+
clean:
24+
rm -rf $(OUTDIR)
25+
docker rm $(NAME) || true
26+
docker rmi $(IMAGE) || true

Diff for: README.md

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Compile for AWS Lambda
2+
3+
## Overview
4+
5+
For a native executable to run in an AWS Lambda function, it must be compatible
6+
with the runtime's operating system. This repository is an example of using
7+
Docker to build a custom C++ executable that runs on AWS Lambda.
8+
9+
## Requirements
10+
11+
- [Docker](https://docs.docker.com/)
12+
- [Make](https://www.gnu.org/software/make/)
13+
14+
## Usage
15+
16+
Enter this directory and run `make`:
17+
18+
```console
19+
$ cd /path/to/compile-for-aws-lambda
20+
$ make
21+
```
22+
23+
The `build` directory now contains binaries that can be packaged in the ZIP file
24+
for an AWS Lambda function:
25+
26+
```
27+
$ tree build
28+
build
29+
├── libsndfile.so -> libsndfile.so.1
30+
├── libsndfile.so.1 -> libsndfile.so.1.0.29
31+
├── libsndfile.so.1.0.29
32+
└── sine
33+
```
34+
35+
The example `sine` program generates a sine wave at the specified frequency (Hz)
36+
and writes it as a WAV file:
37+
```console
38+
$ cd build
39+
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
40+
$ ./sine 2600 /tmp/2600.wav
41+
$ file /tmp/2600.wav
42+
2600.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 24 bit, mono 44100 Hz
43+
```
44+
45+
To run the program in a Lambda function, use the
46+
[child_process](https://nodejs.org/docs/latest-v12.x/api/child_process.html)
47+
module in Node.js, or the
48+
[subprocess](https://docs.python.org/3.8/library/subprocess.html) module in
49+
Python.
50+
51+
## Details
52+
53+
From the [Running Arbitrary Executables in AWS
54+
Lambda](https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/)
55+
blog post:
56+
57+
> If you compile your own binaries, ensure that they’re either statically linked
58+
> or built for the matching version of Amazon Linux.
59+
60+
The example `sine` program in this repository uses the LGPL-licensed
61+
[libsndfile](https://github.com/erikd/libsndfile) library. To comply with the
62+
LPGL, libsndfile must be used as a shared library; it cannot be statically
63+
linked.
64+
65+
### Dockerfile
66+
67+
To compile binaries that are compatible with Amazon Linux 2, the
68+
[`Dockerfile`](./Dockerfile) starts from an Amazon Linux 2 base image:
69+
70+
```docker
71+
FROM amazonlinux:2.0.20200406.0
72+
```
73+
74+
The Dockerfile then builds and installs `libsndfile` and `sine`.
75+
76+
Binaries compiled in this environment will run on any AWS Lambda runtime that's
77+
based on Amazon Linux 2, such as the Node.js 12 and Python 3.8 runtimes. See
78+
[AWS Lambda
79+
runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) for
80+
a complete list.
81+
82+
### Makefile
83+
84+
The [`Makefile`](./Makefile) creates a container from the Docker image and
85+
copies the built artifacts from the container to the host system.

Diff for: sine/CMakeLists.txt

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
3+
project(sine LANGUAGES CXX)
4+
5+
find_package(SndFile REQUIRED)
6+
7+
add_subdirectory(src)
8+
add_subdirectory(app)

Diff for: sine/app/CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_executable(sine sine.cpp)
2+
3+
target_link_libraries(sine PRIVATE libsine)
4+
5+
install(TARGETS sine
6+
RUNTIME DESTINATION bin)

Diff for: sine/app/sine.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <libsine/libsine.h>
2+
3+
#include <cstdlib>
4+
#include <iostream>
5+
#include <string>
6+
7+
int main(int argc, char * argv[]) {
8+
if (argc != 3) {
9+
std::cerr << "USAGE: " << argv[0] << " <frequency (Hz)> <filename>" << std::endl;
10+
return 1;
11+
}
12+
13+
// Parse arguments
14+
float frequency = atof(argv[1]);
15+
std::string filename(argv[2]);
16+
17+
// Generate WAV file
18+
auto result = sine::generate_sine(frequency, filename);
19+
20+
return result ? 0 : 1;
21+
}

Diff for: sine/include/libsine/libsine.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef LIBSINE_H
2+
#define LIBSINE_H
3+
4+
#include <string>
5+
6+
namespace sine
7+
{
8+
9+
// Generate a mono WAV file of a sine function at the specified frequency.
10+
// Returns true on success.
11+
bool generate_sine(float frequency, const std::string & filename);
12+
13+
} // namespace sine
14+
15+
#endif // LIBSINE_H

Diff for: sine/src/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
add_library(libsine STATIC libsine.cpp ../include/libsine/libsine.h)
2+
3+
target_include_directories(libsine PUBLIC ../include)
4+
5+
target_compile_features(libsine PUBLIC cxx_std_11)
6+
7+
target_link_libraries(libsine PRIVATE SndFile::sndfile)

Diff for: sine/src/libsine.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <libsine/libsine.h>
2+
3+
#include <cmath>
4+
#include <cstring>
5+
#include <vector>
6+
7+
#include <sndfile.h>
8+
9+
namespace sine
10+
{
11+
12+
static constexpr int SampleRate = 44100;
13+
static constexpr int SampleCount = (SampleRate * 2); // 2 seconds
14+
static constexpr float Amplitude = (1.0 * 0x7F000000);
15+
16+
// Based on libsndfile example:
17+
// https://github.com/erikd/libsndfile/blob/06ebde5/examples/make_sine.c
18+
bool generate_sine(float frequency, const std::string & filename)
19+
{
20+
if (frequency < 0.0f) {
21+
return false;
22+
}
23+
24+
frequency /= SampleRate;
25+
26+
SF_INFO sfinfo;
27+
memset(&sfinfo, 0, sizeof(sfinfo));
28+
sfinfo.samplerate = 44100;
29+
sfinfo.frames = SampleCount;
30+
sfinfo.channels = 1;
31+
sfinfo.format = (SF_FORMAT_WAV | SF_FORMAT_PCM_24);
32+
33+
SNDFILE * file = sf_open(filename.c_str(), SFM_WRITE, &sfinfo);
34+
if (!file) {
35+
return false;
36+
}
37+
38+
std::vector<int> buffer(SampleCount);
39+
40+
for (int i = 0 ; i < SampleCount ; i++) {
41+
buffer[i] = Amplitude * sin(frequency * 2 * i * M_PI);
42+
}
43+
44+
if (sf_write_int(file, &buffer[0], sfinfo.channels * SampleCount) != sfinfo.channels * SampleCount) {
45+
return false;
46+
}
47+
48+
sf_close(file);
49+
50+
return true;
51+
}
52+
53+
} // namespace sine

0 commit comments

Comments
 (0)